From 92a736f5e06473d454f197b8017dc542ba8c404c Mon Sep 17 00:00:00 2001 From: Nemil Dalal Date: Mon, 23 Nov 2015 16:02:00 -0500 Subject: Added solidity --- solidity.html.markdown | 381 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 381 insertions(+) create mode 100644 solidity.html.markdown (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown new file mode 100644 index 00000000..6409828a --- /dev/null +++ b/solidity.html.markdown @@ -0,0 +1,381 @@ +--- +language: Solidity +filename: learnSolidity.sol +contributors: + - ["Nemil Dalal", "https://www.nemil.com"] +--- + +Solidity is a statically typed, contract programming language for [Ethereum](https://www.ethereum.org/) that has similarities to Javascript and C. Like an object in object-oriented languages, each contract contains state variables, functions, and common data types. Contract-specific features include modifier (guard) clauses, event notifiers, and custom variables. + +Solidity lets you program on Ethereum, a blockchain-based virtual machine that allows the creation and computation of smart contracts, without needing centralized or trusted parties. + +As Solidity and Ethereum are under active development, experimental or beta features are explicitly marked, and subject to change. Pull requests welcome. + +```javascript +// Let's start with a simple Bank contract, before diving into to the key components of the language + +// Start with a Natspec comment (the three slashes) that can be used +// for documentation - and as descriptive data for UI elements +/// @title A simple deposit/withdrawal bank built on Bitcoin + +// All contracts are declared and named (in CamelCase) +contract AcmeBank { + // Declare state variables outside a function, + // these are persistent throughout the life of the contract + + // a dictionary that maps addresses to balances + mapping (address -> uint) balances; + + // the 'public' makes 'owner' externally readable by users or contracts + // (but not writeable), the 'constant' means this value to be + // changed after initialization + address public constant owner; + + // Constructor, can receive one or many variables here + function AcmeBank() { + // msg is a default variable that provides both the + // contract messager's address and amount + owner = msg.address; + // the owner has no additional rights, we're setting it for + // illustrative purposes + } + + function deposit(uint balance) { + balances[msg.sender] += msg.value; // no need for "this." or "self." in front of the state variable + + return balances[msg.sender]; + } + + function withdraw(uint withdrawAmount) returns (uint remainingBalance) { + if(balances[msg.sender] >= withdrawAmount) { + balances[msg.sender] -= withdrawAmount; + balances[msg.sender].send(withdrawAmount); + + return balances[msg.sender]; + } + } + + // The 'constant' prevents the function from editing state variables + function balance() constant { + return balances[msg.sender]; + } + + // Fallback function + // This function is called if invalid data is sent or ether without data; + // Added so that ether sent to this contract is reverted if the contract fails + // otherwise, the sender loses their money; you should add this in most contracts + function () { throw; } +} +// End example + +// Now let's go through the basics of Solidity + +// 1. DATA TYPES +// uint is the data type typically used for currency (there are no doubles +// or floats) and for dates +uint x; +int const a = 8; // int of 256 bits, cannot be changed after instantiation +uint8 b; +int64 c; +// int256 is same as int +// For both int and uint, you can explicitly set space in steps of 8, +// e.g., int8, int16 +uint248 e; + +// Type casting +int x = int(b) + +bool b = true; // or do 'var b = true;' for inferred typing + +// Addresses - holds 20 byte/160 bit Ethereum addresses to another contract +// ('Contract Account)') or person/external entity ('External Account') +address public owner; // Add 'public' field to indicate publicly/externally accessible, a getter is automatically created, but NOT a setter + +// All addresses can be sent ether in the following way: +owner.send(SOME_BALANCE); // returns false on failure +owner.balance; // the balance of the owner + +// Bytes are provided from 1 to 32 +byte a; // byte is same as bytes1 +bytes32 b; + +// Dynamically sized +bytes m; // A special array, same as byte[] (but packed tightly) +// same as bytes, but does not allow length or index access (for now) +string n = 'hello'; + +// Type inference +// var does inferred typing based on first assignment, +// can't be used in functions parameters +var a = true; +// there are edge cases where inference leads to a value being set (e.g., an uint 8) +// that is different from what the user wanted (uint16), so use carefully + +// by default, all values are set to 0 on instantiation + +// Delete can be called on most types, and will set the values to 0 +uint x = 5; +delete(x); // x is now 0 + +// 2. DATA STRUCTURES +// Arrays +bytes32[] names; +uint newLength = names.push("John"); // adding returns new length of the array +// Length +names.length; // get length +names.length = 1; // lengths can also be set, unlike many other languages + +// Dictionaries (any type to any other type) +mapping (string -> uint) public balances; +balances["john"] = 1; +console.log(balances[jill]); // is 0, all non-set key values return zeroes +// The 'public' lets you do the following from another contract +contractName.balances("john"); // returns 1 +// The 'public' keyword here created a getter (but not setter) that behaves like the following: +function balances(address _account) returns (uint balance) { + return balances[_account]; +} + +// To delete +delete(balances["John"]); +delete(balances); // deletes all elements + +// Unlike languages like Javascript, you cannot iterate through all elements in +// a map, without knowing the source keys + +// Structs and enums + struct Bank { // note the capital + address owner; + uint balance; + } +Bank b = Bank({ + owner: msg.sender, + balance: 5 +}); +delete(b); // set all values to 0, except any mappings + +// Enums +enum State { Created, Locked, Inactive }; +State public state; // Declare variable from enum +state = State.Created; + +// 3. Variables of note +// storage - A persistent storage hash (does not need to be declared) +storage['abc'] = 'def'; // maps 256 bit words to 256 bit words + +// tx - This transaction +tx.origin // address, sender of the transaction +tx.gasprice // uint, gas price of the transaction + +// msg - The current message received by the contract +msg.sender; // address, The address of the sender +msg.value; // uint, The amount of gas provided to this contract in wei +msg.data // bytes, complete call data + +// balance of the current contract (both contract and external accounts +// have balances) - often used at the end of a contracts life to send the +// remaining balance to a party +this.balance +// block +now // uint, current time, alias for block.timestamp +block.number // uint, current block number +block.difficulty // uint, current block difficulty +block.blockhash(1) // returns bytes32, only provides for most recent 256 block + +// 4. FUNCTIONS AND MORE +// A. Functions +// Simple function +function increment(uint x) returns (uint) { + x += 1; + return x; +} + +// Functions can return many arguments, and by specifying the returned arguments +// you don't need to explicity return +function increment(uint x, uint y) returns (uint x, uint y) { + x += 1; + y += 1; +} +// This function would have been called like this, and assigned to a tuple +uint (a,b) = increment(1,1); + +// The 'constant' indicates and ensures that a function does not/cannot change the persistent variables +uint y; + +function increment(uint x) constant returns (uint x) { + x += 1; + y += 1; // this line would fail + // as y is a state variable, and can't be changed in a constant function +} + +// There are a few 'function visibility specifiers' that can be placed where 'constant' +// is, which include: +// internal (can only be called by an internal function, not one external to the contract) +// public - visibile externally and internally +// private - only visible in the current contract + +// Functions are hoisted (so you can call a function, even if it is declared later) - and you can assign a function to a variable +function a() { + var z = b; + b(); +} + +function b() { + +} + +// B. Events +// Events are an easy way to notify external listeners that something changed +// You typically decalre them after your contract parameters +event Sent(address from, address to, uint amount); + +// You then call it in a function, when you want to trigger it +sent(from, to, amount); + +// For an external party (a contract or external entity), to watch +// for an event, you write the following: +Coin.Sent().watch({}, '', function(error, result) { + if (!error) { + console.log("Coin transfer: " + result.args.amount + + " coins were sent from " + result.args.from + + " to " + result.args.to + "."); + console.log("Balances now:\n" + + "Sender: " + Coin.balances.call(result.args.from) + + "Receiver: " + Coin.balances.call(result.args.to)); + } +} +// This is a common paradigm for one contract to depend on another (e.g., a +// contract that depends on the current exchange rate provided by another +// contract) + +// C. Modifiers +// Modifiers let you validate inputs to functions +// The '_' (underscore) must be included, and is an indicator that the +// function being called should be placed there +modifier onlyBefore(uint _time) { if (now >= _time) throw; _ } + +// You can then append it right after the function declaration +function test() + onlyBefore() +{ + +} + +// 5. BRANCHING AND LOOPS + +// All basic logic blocks work - including if/else, for, while, break, continue, return +// switch is not provided +// Syntax is the same as javascript, but there is no type conversion from +// non-boolean to boolean + +// 6. CALLING AN EXTERNAL CONTRACT + +contract infoFeed { + function info() returns (uint ret) { return 42; } +} + +contract Consumer { + InfoFeed feed; // create a variable that will point to a contract on the blockchain + function setFeed(address addr) { + // Link to the contract by creating on the address + feed = InfoFeed(addr); + } + function callFeed() { + // T final parentheses call the contract, optionally adding + // custom value or gas numbers + feed.info.value(10).gas(800)(); + } +} + +// 7. CONTRACT DESIGN PATTERNS + +// A. Obfuscation +// Remember that all variables are publicly viewable on the blockchain, so +// anything that needs some privacy needs to be obfuscated (e.g., hashed) + +// B. Throwing +// Throwing +throw; // throwing is easily done, and reverts unused money to the sender +// You can't currently catch + +// A common design pattern is: +if (!addr.send(123)) { + throw; +} + +// C. Suicide +// Suicide +suicide(SOME_ADDRESS); // suicide the current contract, sending funds to the address (often the creator) + +// D. Storage optimization +// Reading and writing can be expensive, as data needs to be stored in the +// blockchain forever - this encourages smart ways to use memory (eventually, +// compilation may better handle this, but for now there are benefits to +// planning your data structures) + +// *** EXAMPLE: Let's do a more complex example *** +// [TODO: Decide what a more complex example looks like, needs a few // characteristics: +// - has a 'constant' state variable +// - has a state machine (uses modifier) +// - sends money to an address +// - gets information from another contract (we'll show code for both contracts) +// - Shows inheritance +// - show variables being passed in on instantiation (and guard code to throw if variables not provided) +// Ideas: +// - crowdfunding? +// - Peer to peer insurance +// ] + +// *** END EXAMPLE *** + +// Some final points +// 7. NATIVE FUNCTIONS + +// Currency units +// By default, currency is defined using wei, the smallest unit of Ether +uint minAmount = 1 wei; +uint a = 1 finney; // 1 ether = 1000 finney +// There are a number of other units, see: http://ether.fund/tool/converter + +// Time units +1 == 1 second +1 minutes == 60 seconds + + +// You typically multiply a variable times the unit, as these units are not +// directly stored in a variable +uint x = 5; +(x * 1 days); // 5 days + +// Be careful about leap seconds and leap years when using equality statements for time (instead, prefer greater than/less than) + +// Cryptography +// All strings passed are concatenated before the hash is run +sha3("ab", "cd"); +ripemd160("abc"); +sha256("def"); + +// These are natspec comments, when a user is asked to confirm a transaction +/// +/** */ + +// 8. COMMON MISTAKES +// A few common mistakes +// You cannot restrict a human or computer from reading the content of +// your transaction or a transaction's state + +// All data to the start of time is stored in the blockchain, so you and +// anyone can observe all previous data states + +// 9. STYLE NOTES +// Use 4 spaces for indentation +// (Python's PEP8 is used as the baseline style guide, including its general philosophy) +``` + +## Additional resources +- [Solidity Docs](https://ethereum.github.io/solidity/docs/home/) +- [Solidity Style Guide](https://ethereum.github.io/solidity//docs/style-guide/): Ethereum's style guide is heavily derived from Python's [pep8](https://www.python.org/dev/peps/pep-0008/) style guide. +- [Browser-based Solidity Editor](http://chriseth.github.io/browser-solidity/) +- [Gitter Chat room](https://gitter.im/ethereum/go-ethereum) + +Feel free to send a pull request with any edits - or email nemild -/at-/ gmail \ No newline at end of file -- cgit v1.2.3 From d5bcbceb21954d0f8739fb841fc511aa32c2bcc6 Mon Sep 17 00:00:00 2001 From: Nemil Dalal Date: Mon, 23 Nov 2015 16:07:17 -0500 Subject: Fixed withdrawal check --- solidity.html.markdown | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index 6409828a..79debed6 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -49,7 +49,10 @@ contract AcmeBank { function withdraw(uint withdrawAmount) returns (uint remainingBalance) { if(balances[msg.sender] >= withdrawAmount) { balances[msg.sender] -= withdrawAmount; - balances[msg.sender].send(withdrawAmount); + + if (!balances[msg.sender].send(withdrawAmount)) { + balances[msg.sender] += withdrawAmount; + } return balances[msg.sender]; } -- cgit v1.2.3 From 08f3ee3687fc18286fdb3825f0fc1fd74c086798 Mon Sep 17 00:00:00 2001 From: Nemil Dalal Date: Mon, 23 Nov 2015 16:39:05 -0500 Subject: Added remove function --- solidity.html.markdown | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index 79debed6..bcbdec5f 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -35,15 +35,13 @@ contract AcmeBank { function AcmeBank() { // msg is a default variable that provides both the // contract messager's address and amount - owner = msg.address; - // the owner has no additional rights, we're setting it for - // illustrative purposes + owner = msg.address; // msg.address refers to the address of the contract creator } function deposit(uint balance) { balances[msg.sender] += msg.value; // no need for "this." or "self." in front of the state variable - return balances[msg.sender]; + return balances[msg.sender]; // msg.sender refers to the contract caller } function withdraw(uint withdrawAmount) returns (uint remainingBalance) { @@ -58,6 +56,13 @@ contract AcmeBank { } } + // It's good practice to have a remove function, which disables this contract + function remove () { + if(msg.sender == owner) { // Only let the contract creator do this + suicide(owner); // suicide makes this contract inactive, and returns funds to the owner + } + } + // The 'constant' prevents the function from editing state variables function balance() constant { return balances[msg.sender]; -- cgit v1.2.3 From 1f4738cbc75f789992270c3926cf9cdd30c4674a Mon Sep 17 00:00:00 2001 From: Nemil Dalal Date: Tue, 24 Nov 2015 00:09:10 -0500 Subject: Several fixes per Andreas's feedback --- solidity.html.markdown | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index bcbdec5f..88ccd817 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -14,28 +14,30 @@ As Solidity and Ethereum are under active development, experimental or beta feat ```javascript // Let's start with a simple Bank contract, before diving into to the key components of the language +// START EXAMPLE // Start with a Natspec comment (the three slashes) that can be used // for documentation - and as descriptive data for UI elements /// @title A simple deposit/withdrawal bank built on Bitcoin // All contracts are declared and named (in CamelCase) +// They are similar to 'class' in other languages (and allow capabilities like inheritance) contract AcmeBank { // Declare state variables outside a function, // these are persistent throughout the life of the contract // a dictionary that maps addresses to balances - mapping (address -> uint) balances; + mapping (address => uint) balances; // the 'public' makes 'owner' externally readable by users or contracts // (but not writeable), the 'constant' means this value to be // changed after initialization - address public constant owner; + address public owner; // Constructor, can receive one or many variables here function AcmeBank() { // msg is a default variable that provides both the // contract messager's address and amount - owner = msg.address; // msg.address refers to the address of the contract creator + owner = msg.sender; // msg.sender refers to the address of the contract creator } function deposit(uint balance) { @@ -48,7 +50,7 @@ contract AcmeBank { if(balances[msg.sender] >= withdrawAmount) { balances[msg.sender] -= withdrawAmount; - if (!balances[msg.sender].send(withdrawAmount)) { + if (!msg.sender.send(withdrawAmount)) { balances[msg.sender] += withdrawAmount; } @@ -56,7 +58,7 @@ contract AcmeBank { } } - // It's good practice to have a remove function, which disables this contract + // It's good practice to have a remove function, which disables this contract - but does mean that users have to trust the owner function remove () { if(msg.sender == owner) { // Only let the contract creator do this suicide(owner); // suicide makes this contract inactive, and returns funds to the owner @@ -74,7 +76,7 @@ contract AcmeBank { // otherwise, the sender loses their money; you should add this in most contracts function () { throw; } } -// End example +// END EXAMPLE // Now let's go through the basics of Solidity @@ -82,7 +84,7 @@ contract AcmeBank { // uint is the data type typically used for currency (there are no doubles // or floats) and for dates uint x; -int const a = 8; // int of 256 bits, cannot be changed after instantiation +int constant a = 8; // int of 256 bits, cannot be changed after instantiation uint8 b; int64 c; // int256 is same as int @@ -134,7 +136,7 @@ names.length; // get length names.length = 1; // lengths can also be set, unlike many other languages // Dictionaries (any type to any other type) -mapping (string -> uint) public balances; +mapping (string => uint) public balances; balances["john"] = 1; console.log(balances[jill]); // is 0, all non-set key values return zeroes // The 'public' lets you do the following from another contract @@ -322,13 +324,14 @@ suicide(SOME_ADDRESS); // suicide the current contract, sending funds to the add // planning your data structures) // *** EXAMPLE: Let's do a more complex example *** -// [TODO: Decide what a more complex example looks like, needs a few // characteristics: +// [TODO: Decide what a more complex example looks like, needs a few characteristics: // - has a 'constant' state variable // - has a state machine (uses modifier) // - sends money to an address // - gets information from another contract (we'll show code for both contracts) // - Shows inheritance // - show variables being passed in on instantiation (and guard code to throw if variables not provided) +// - Shows the swapping out of a contract // Ideas: // - crowdfunding? // - Peer to peer insurance @@ -375,7 +378,9 @@ sha256("def"); // All data to the start of time is stored in the blockchain, so you and // anyone can observe all previous data states -// 9. STYLE NOTES +// 9. TESTING + +// 10. STYLE NOTES // Use 4 spaces for indentation // (Python's PEP8 is used as the baseline style guide, including its general philosophy) ``` -- cgit v1.2.3 From 700f3e7a1cb6ef5b905eac7ec3fe3aa2e713c079 Mon Sep 17 00:00:00 2001 From: Nemil Dalal Date: Mon, 30 Nov 2015 15:45:03 -0500 Subject: Many minor updates --- solidity.html.markdown | 226 +++++++++++++++++++++++++++++++------------------ 1 file changed, 145 insertions(+), 81 deletions(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index 88ccd817..0fa1fddc 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -14,7 +14,7 @@ As Solidity and Ethereum are under active development, experimental or beta feat ```javascript // Let's start with a simple Bank contract, before diving into to the key components of the language -// START EXAMPLE +// ** START EXAMPLE ** // Start with a Natspec comment (the three slashes) that can be used // for documentation - and as descriptive data for UI elements /// @title A simple deposit/withdrawal bank built on Bitcoin @@ -22,31 +22,30 @@ As Solidity and Ethereum are under active development, experimental or beta feat // All contracts are declared and named (in CamelCase) // They are similar to 'class' in other languages (and allow capabilities like inheritance) contract AcmeBank { - // Declare state variables outside a function, + // Declare state variables outside a function, // these are persistent throughout the life of the contract // a dictionary that maps addresses to balances - mapping (address => uint) balances; + mapping (address => uint) balances; + + // the 'public' makes 'owner' externally readable by users or contracts + // (but not writeable) - + address public owner; - // the 'public' makes 'owner' externally readable by users or contracts - // (but not writeable), the 'constant' means this value to be - // changed after initialization - address public owner; - // Constructor, can receive one or many variables here function AcmeBank() { - // msg is a default variable that provides both the + // msg is a default variable that provides both the // contract messager's address and amount owner = msg.sender; // msg.sender refers to the address of the contract creator } - - function deposit(uint balance) { + + function deposit(uint balance) public { balances[msg.sender] += msg.value; // no need for "this." or "self." in front of the state variable return balances[msg.sender]; // msg.sender refers to the contract caller } - function withdraw(uint withdrawAmount) returns (uint remainingBalance) { + function withdraw(uint withdrawAmount) public returns (uint remainingBalance) { if(balances[msg.sender] >= withdrawAmount) { balances[msg.sender] -= withdrawAmount; @@ -58,8 +57,9 @@ contract AcmeBank { } } - // It's good practice to have a remove function, which disables this contract - but does mean that users have to trust the owner - function remove () { + // It's good practice to have a remove function, which disables this + // contract - but does mean that users have to trust the owner + function remove() { if(msg.sender == owner) { // Only let the contract creator do this suicide(owner); // suicide makes this contract inactive, and returns funds to the owner } @@ -71,29 +71,35 @@ contract AcmeBank { } // Fallback function - // This function is called if invalid data is sent or ether without data; + // The fallback function is called if none of the other functions matches the given function identifier. + // It is often meant to be called when invalid data is sent or ether without data. // Added so that ether sent to this contract is reverted if the contract fails // otherwise, the sender loses their money; you should add this in most contracts function () { throw; } } -// END EXAMPLE +// ** END EXAMPLE ** // Now let's go through the basics of Solidity -// 1. DATA TYPES +// 1. DATA TYPES AND ASSOCIATED METHOD // uint is the data type typically used for currency (there are no doubles // or floats) and for dates -uint x; -int constant a = 8; // int of 256 bits, cannot be changed after instantiation +uint x; + + +// with 'constant', the compiler replaces each occurence with the acutal value +// int of 256 bits, cannot be changed after instantiation +int constant a = 8; +int256 constant a = 8; // same effect as line above, here the 256 is explict + +// For both int and uint, you can explicitly set space in steps of 8 +// e.g., int8, int16 uint8 b; int64 c; -// int256 is same as int -// For both int and uint, you can explicitly set space in steps of 8, -// e.g., int8, int16 uint248 e; // Type casting -int x = int(b) +int x = int(b); bool b = true; // or do 'var b = true;' for inferred typing @@ -115,21 +121,22 @@ bytes m; // A special array, same as byte[] (but packed tightly) string n = 'hello'; // Type inference -// var does inferred typing based on first assignment, +// var does inferred typing based on first assignment, // can't be used in functions parameters var a = true; -// there are edge cases where inference leads to a value being set (e.g., an uint 8) +// there are edge cases where inference leads to a value being set (e.g., an uint 8) // that is different from what the user wanted (uint16), so use carefully // by default, all values are set to 0 on instantiation -// Delete can be called on most types, and will set the values to 0 +// Delete can be called on most types, and will set the values to 0 by assignment uint x = 5; delete(x); // x is now 0 // 2. DATA STRUCTURES // Arrays -bytes32[] names; +bytes32[5] nicknames; // static array +bytes32[] names; // dynamic array uint newLength = names.push("John"); // adding returns new length of the array // Length names.length; // get length @@ -153,13 +160,13 @@ delete(balances); // deletes all elements // Unlike languages like Javascript, you cannot iterate through all elements in // a map, without knowing the source keys -// Structs and enums +// Structs and enums struct Bank { // note the capital address owner; uint balance; } Bank b = Bank({ - owner: msg.sender, + owner: msg.sender, balance: 5 }); delete(b); // set all values to 0, except any mappings @@ -168,29 +175,39 @@ delete(b); // set all values to 0, except any mappings enum State { Created, Locked, Inactive }; State public state; // Declare variable from enum state = State.Created; +// enums can be explicitly converted to ints -// 3. Variables of note -// storage - A persistent storage hash (does not need to be declared) -storage['abc'] = 'def'; // maps 256 bit words to 256 bit words +// Data locations: Memory vs. storage - all complex types (arrays, structs) have a data location +// 'memory' does not persist, 'storage' does +// Default is 'storage' for local and state variables; 'memory' for function parameters -// tx - This transaction -tx.origin // address, sender of the transaction -tx.gasprice // uint, gas price of the transaction +// 3. Variables of note +// ** this ** +this; // the address of the current contract +// 'balance' often used at the end of a contracts life to send the +// remaining balance to a party +this.balance; +this.someFunction(); // calls a function externally (via a message call, not via an internal jump) -// msg - The current message received by the contract +// ** msg - The current message received by the contract ** ** msg.sender; // address, The address of the sender msg.value; // uint, The amount of gas provided to this contract in wei -msg.data // bytes, complete call data +msg.data; // bytes, complete call data +msg.gas; // remaining gas -// balance of the current contract (both contract and external accounts -// have balances) - often used at the end of a contracts life to send the -// remaining balance to a party -this.balance -// block +// ** tx - This transaction ** +tx.origin; // address, sender of the transaction +tx.gasprice; // uint, gas price of the transaction + +// ** block - Information about the current block ** now // uint, current time, alias for block.timestamp -block.number // uint, current block number -block.difficulty // uint, current block difficulty -block.blockhash(1) // returns bytes32, only provides for most recent 256 block +block.number; // uint, current block number +block.difficulty; // uint, current block difficulty +block.blockhash(1); // returns bytes32, only provides for most recent 256 blocks +block.gasLimit(); + +// ** storage - A persistent storage hash (does not need to be declared) ** +storage['abc'] = 'def'; // maps 256 bit words to 256 bit words // 4. FUNCTIONS AND MORE // A. Functions @@ -236,13 +253,13 @@ function b() { // B. Events // Events are an easy way to notify external listeners that something changed -// You typically decalre them after your contract parameters +// You typically declare them after your contract parameters event Sent(address from, address to, uint amount); // You then call it in a function, when you want to trigger it sent(from, to, amount); -// For an external party (a contract or external entity), to watch +// For an external party (a contract or external entity), to watch // for an event, you write the following: Coin.Sent().watch({}, '', function(error, result) { if (!error) { @@ -254,53 +271,89 @@ Coin.Sent().watch({}, '', function(error, result) { "Receiver: " + Coin.balances.call(result.args.to)); } } -// This is a common paradigm for one contract to depend on another (e.g., a +// This is a common paradigm for one contract to depend on another (e.g., a // contract that depends on the current exchange rate provided by another // contract) // C. Modifiers -// Modifiers let you validate inputs to functions -// The '_' (underscore) must be included, and is an indicator that the +// Modifiers let you validate inputs to functions such as a minimal balance or user authentication +// It's similar to a guard clause in other languages + +// The '_' (underscore) must be included as the last line in the function body, and is an indicator that the // function being called should be placed there modifier onlyBefore(uint _time) { if (now >= _time) throw; _ } // You can then append it right after the function declaration -function test() - onlyBefore() -{ - +function changeOwner(newOwner) + onlyBefore(someTime) + { + owner = newOwner; } // 5. BRANCHING AND LOOPS // All basic logic blocks work - including if/else, for, while, break, continue, return // switch is not provided -// Syntax is the same as javascript, but there is no type conversion from -// non-boolean to boolean -// 6. CALLING AN EXTERNAL CONTRACT +// Syntax is the same as javascript, but there is no type conversion from +// non-boolean to boolean, so comparison operators must be used to get the boolean value + +// 6. OBJECTS/CONTRACTS +// A. Calling an external contract contract infoFeed { function info() returns (uint ret) { return 42; } } contract Consumer { InfoFeed feed; // create a variable that will point to a contract on the blockchain - function setFeed(address addr) { + + // Set feed to an existing contract + function setFeed(address addr) { // Link to the contract by creating on the address - feed = InfoFeed(addr); + feed = InfoFeed(addr); } - function callFeed() { - // T final parentheses call the contract, optionally adding + + // Set feed based to a new instance of the contract + function createNewFeed() { + feed = new InfoFeed(); + } + + function callFeed() { + // T final parentheses call the contract, optionally adding // custom value or gas numbers feed.info.value(10).gas(800)(); } } +// B. Inheritance + +// Order matters, last inherited contract (i.e., 'def') can override parts of the previously +// inherited contracts +contact MyContract is abc, def("a custom argument to def") { + +// Override function + + function z() { + if (msg.sender == owner) { + def.z(); // call overridden function + } + } + + }; + +// C. Import + +import "filename"; +import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol"; + +// Importing is under active development and will change +// Importing cannot currently be done at the command line + // 7. CONTRACT DESIGN PATTERNS // A. Obfuscation -// Remember that all variables are publicly viewable on the blockchain, so +// Remember that all variables are publicly viewable on the blockchain, so // anything that needs some privacy needs to be obfuscated (e.g., hashed) // B. Throwing @@ -317,26 +370,34 @@ if (!addr.send(123)) { // Suicide suicide(SOME_ADDRESS); // suicide the current contract, sending funds to the address (often the creator) +// This is a common pattern that lets the owner end the contract +function remove() { + if(msg.sender == owner) { // Only let the contract creator do this + suicide(owner); // suicide makes this contract inactive, and returns funds to the owner + } +} + // D. Storage optimization -// Reading and writing can be expensive, as data needs to be stored in the -// blockchain forever - this encourages smart ways to use memory (eventually, -// compilation may better handle this, but for now there are benefits to +// Reading and writing can be expensive, as data needs to be stored in the +// blockchain forever - this encourages smart ways to use memory (eventually, +// compilation may better handle this, but for now there are benefits to // planning your data structures) // *** EXAMPLE: Let's do a more complex example *** + +// ** START EXAMPLE ** // [TODO: Decide what a more complex example looks like, needs a few characteristics: // - has a 'constant' state variable -// - has a state machine (uses modifier) +// - has a state machine (and uses modifier) // - sends money to an address // - gets information from another contract (we'll show code for both contracts) // - Shows inheritance // - show variables being passed in on instantiation (and guard code to throw if variables not provided) -// - Shows the swapping out of a contract +// - Shows the swapping out of a contract address // Ideas: // - crowdfunding? // - Peer to peer insurance // ] - // *** END EXAMPLE *** // Some final points @@ -353,7 +414,7 @@ uint a = 1 finney; // 1 ether = 1000 finney 1 minutes == 60 seconds -// You typically multiply a variable times the unit, as these units are not +// You typically multiply a variable times the unit, as these units are not // directly stored in a variable uint x = 5; (x * 1 days); // 5 days @@ -366,22 +427,22 @@ sha3("ab", "cd"); ripemd160("abc"); sha256("def"); -// These are natspec comments, when a user is asked to confirm a transaction -/// -/** */ +// 8. COMMON MISTAKES/MISCONCEPTIONS +// A few common mistakes and misconceptions: -// 8. COMMON MISTAKES -// A few common mistakes -// You cannot restrict a human or computer from reading the content of +// A. You cannot restrict a human or computer from reading the content of // your transaction or a transaction's state -// All data to the start of time is stored in the blockchain, so you and -// anyone can observe all previous data states +// All data to the start of time is stored in the blockchain, so you and +// anyone can observe all previous data stats -// 9. TESTING +// When you don't specify public on a variable, you are indicating that other *contracts* can't +// read the data - but any person can still read the data -// 10. STYLE NOTES -// Use 4 spaces for indentation +// TODO + +// 9. STYLE NOTES +// Use 4 spaces for indentation // (Python's PEP8 is used as the baseline style guide, including its general philosophy) ``` @@ -391,4 +452,7 @@ sha256("def"); - [Browser-based Solidity Editor](http://chriseth.github.io/browser-solidity/) - [Gitter Chat room](https://gitter.im/ethereum/go-ethereum) -Feel free to send a pull request with any edits - or email nemild -/at-/ gmail \ No newline at end of file +## Information purposefully excluded +- Libraries + +Feel free to send a pull request with any edits - or email nemild -/at-/ gmail -- cgit v1.2.3 From ec6172fc5e904c65e672ca22bbc6102a94a60ec9 Mon Sep 17 00:00:00 2001 From: Nemil Dalal Date: Mon, 30 Nov 2015 15:48:47 -0500 Subject: Formatting --- solidity.html.markdown | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index 0fa1fddc..2adfc00b 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -81,12 +81,12 @@ contract AcmeBank { // Now let's go through the basics of Solidity -// 1. DATA TYPES AND ASSOCIATED METHOD + +// 1. DATA TYPES AND ASSOCIATED METHODS // uint is the data type typically used for currency (there are no doubles // or floats) and for dates uint x; - // with 'constant', the compiler replaces each occurence with the acutal value // int of 256 bits, cannot be changed after instantiation int constant a = 8; @@ -133,6 +133,7 @@ var a = true; uint x = 5; delete(x); // x is now 0 + // 2. DATA STRUCTURES // Arrays bytes32[5] nicknames; // static array @@ -181,6 +182,7 @@ state = State.Created; // 'memory' does not persist, 'storage' does // Default is 'storage' for local and state variables; 'memory' for function parameters + // 3. Variables of note // ** this ** this; // the address of the current contract @@ -209,6 +211,7 @@ block.gasLimit(); // ** storage - A persistent storage hash (does not need to be declared) ** storage['abc'] = 'def'; // maps 256 bit words to 256 bit words + // 4. FUNCTIONS AND MORE // A. Functions // Simple function @@ -290,6 +293,7 @@ function changeOwner(newOwner) owner = newOwner; } + // 5. BRANCHING AND LOOPS // All basic logic blocks work - including if/else, for, while, break, continue, return @@ -298,6 +302,7 @@ function changeOwner(newOwner) // Syntax is the same as javascript, but there is no type conversion from // non-boolean to boolean, so comparison operators must be used to get the boolean value + // 6. OBJECTS/CONTRACTS // A. Calling an external contract @@ -350,6 +355,7 @@ import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol"; // Importing is under active development and will change // Importing cannot currently be done at the command line + // 7. CONTRACT DESIGN PATTERNS // A. Obfuscation @@ -383,6 +389,8 @@ function remove() { // compilation may better handle this, but for now there are benefits to // planning your data structures) + + // *** EXAMPLE: Let's do a more complex example *** // ** START EXAMPLE ** @@ -400,7 +408,7 @@ function remove() { // ] // *** END EXAMPLE *** -// Some final points + // 7. NATIVE FUNCTIONS // Currency units @@ -427,6 +435,7 @@ sha3("ab", "cd"); ripemd160("abc"); sha256("def"); + // 8. COMMON MISTAKES/MISCONCEPTIONS // A few common mistakes and misconceptions: @@ -441,6 +450,7 @@ sha256("def"); // TODO + // 9. STYLE NOTES // Use 4 spaces for indentation // (Python's PEP8 is used as the baseline style guide, including its general philosophy) -- cgit v1.2.3 From 4b7d7e3d2e86e6e2d5b95b518864ecd89392d7c0 Mon Sep 17 00:00:00 2001 From: Nemil Dalal Date: Mon, 30 Nov 2015 16:01:51 -0500 Subject: Spelling and grammar --- solidity.html.markdown | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index 2adfc00b..3e47f080 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -72,7 +72,7 @@ contract AcmeBank { // Fallback function // The fallback function is called if none of the other functions matches the given function identifier. - // It is often meant to be called when invalid data is sent or ether without data. + // Typically, called when invalid data is sent to the contract or ether without data. // Added so that ether sent to this contract is reverted if the contract fails // otherwise, the sender loses their money; you should add this in most contracts function () { throw; } @@ -87,10 +87,10 @@ contract AcmeBank { // or floats) and for dates uint x; -// with 'constant', the compiler replaces each occurence with the acutal value +// with 'constant', the compiler replaces each occurrence with the actual value // int of 256 bits, cannot be changed after instantiation int constant a = 8; -int256 constant a = 8; // same effect as line above, here the 256 is explict +int256 constant a = 8; // same effect as line above, here the 256 is explicit // For both int and uint, you can explicitly set space in steps of 8 // e.g., int8, int16 @@ -221,7 +221,7 @@ function increment(uint x) returns (uint) { } // Functions can return many arguments, and by specifying the returned arguments -// you don't need to explicity return +// you don't need to explicitly return function increment(uint x, uint y) returns (uint x, uint y) { x += 1; y += 1; @@ -241,7 +241,7 @@ function increment(uint x) constant returns (uint x) { // There are a few 'function visibility specifiers' that can be placed where 'constant' // is, which include: // internal (can only be called by an internal function, not one external to the contract) -// public - visibile externally and internally +// public - visible externally and internally // private - only visible in the current contract // Functions are hoisted (so you can call a function, even if it is declared later) - and you can assign a function to a variable -- cgit v1.2.3 From 8ef890b0de22d9fd14572f4ac171a238ea4f3f20 Mon Sep 17 00:00:00 2001 From: Nemil Dalal Date: Mon, 30 Nov 2015 16:14:26 -0500 Subject: Added sample contracts --- solidity.html.markdown | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index 3e47f080..2b461a95 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -462,6 +462,10 @@ sha256("def"); - [Browser-based Solidity Editor](http://chriseth.github.io/browser-solidity/) - [Gitter Chat room](https://gitter.im/ethereum/go-ethereum) +## Sample contracts +- [Solidity Baby Step Contracts](https://github.com/fivedogit/solidity-baby-steps/tree/master/contracts) +- [Consensys Contracts](https://github.com/ConsenSys/dapp-store-contracts) + ## Information purposefully excluded - Libraries -- cgit v1.2.3 From add8f68f1acdceca1b9e09d6458627c515e73047 Mon Sep 17 00:00:00 2001 From: Nemil Dalal Date: Mon, 30 Nov 2015 16:51:53 -0500 Subject: Add exposition around example bank --- solidity.html.markdown | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index 2b461a95..77648e51 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -13,6 +13,10 @@ As Solidity and Ethereum are under active development, experimental or beta feat ```javascript // Let's start with a simple Bank contract, before diving into to the key components of the language +// This bank has three main capabilities: +// - deposit +// - withdrawal +// - check balance // ** START EXAMPLE ** // Start with a Natspec comment (the three slashes) that can be used @@ -57,14 +61,6 @@ contract AcmeBank { } } - // It's good practice to have a remove function, which disables this - // contract - but does mean that users have to trust the owner - function remove() { - if(msg.sender == owner) { // Only let the contract creator do this - suicide(owner); // suicide makes this contract inactive, and returns funds to the owner - } - } - // The 'constant' prevents the function from editing state variables function balance() constant { return balances[msg.sender]; @@ -406,6 +402,14 @@ function remove() { // - crowdfunding? // - Peer to peer insurance // ] + // It's good practice to have a remove function, which disables this + // contract - but does mean that users have to trust the owner + // For a decentralized bank without a trusted part + function remove() { + if(msg.sender == owner) { // Only let the contract creator do this + suicide(owner); // suicide makes this contract inactive, and returns funds to the owner + } + } // *** END EXAMPLE *** -- cgit v1.2.3 From 541c278de4b253090b27a1ef126f5ed27e050f7c Mon Sep 17 00:00:00 2001 From: Nemil Dalal Date: Mon, 30 Nov 2015 17:23:41 -0500 Subject: Minor updates --- solidity.html.markdown | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index 77648e51..298b01f3 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -30,10 +30,13 @@ contract AcmeBank { // these are persistent throughout the life of the contract // a dictionary that maps addresses to balances - mapping (address => uint) balances; + // the private means that other contracts can't see balances + // but the data is still available to all other parties on the + // blockchain + mapping (address => uint) private balances; // the 'public' makes 'owner' externally readable by users or contracts - // (but not writeable) - + // (but not writeable) address public owner; // Constructor, can receive one or many variables here @@ -125,9 +128,10 @@ var a = true; // by default, all values are set to 0 on instantiation -// Delete can be called on most types, and will set the values to 0 by assignment +// Delete can be called on most types +// (it does NOT destroy the value, but rather sets the value to 0 by assignment) uint x = 5; -delete(x); // x is now 0 +delete x; // x is now 0 // 2. DATA STRUCTURES @@ -151,8 +155,8 @@ function balances(address _account) returns (uint balance) { } // To delete -delete(balances["John"]); -delete(balances); // deletes all elements +delete balances["John"]; +delete balances; // deletes all elements // Unlike languages like Javascript, you cannot iterate through all elements in // a map, without knowing the source keys @@ -166,7 +170,7 @@ Bank b = Bank({ owner: msg.sender, balance: 5 }); -delete(b); // set all values to 0, except any mappings +delete b; // set all variables in struct to 0, except any mappings // Enums enum State { Created, Locked, Inactive }; @@ -226,6 +230,7 @@ function increment(uint x, uint y) returns (uint x, uint y) { uint (a,b) = increment(1,1); // The 'constant' indicates and ensures that a function does not/cannot change the persistent variables +// Constant function execute locally, not on the blockchain uint y; function increment(uint x) constant returns (uint x) { @@ -469,6 +474,7 @@ sha256("def"); ## Sample contracts - [Solidity Baby Step Contracts](https://github.com/fivedogit/solidity-baby-steps/tree/master/contracts) - [Consensys Contracts](https://github.com/ConsenSys/dapp-store-contracts) +- [State of Dapps](http://dapps.ethercasts.com/) ## Information purposefully excluded - Libraries -- cgit v1.2.3 From 8d7085893535825ea6879e3f29ee0eb614a16f9b Mon Sep 17 00:00:00 2001 From: Nemil Dalal Date: Fri, 11 Dec 2015 13:07:01 -0500 Subject: Few minor fixes --- solidity.html.markdown | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index 298b01f3..7f925918 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -5,9 +5,9 @@ contributors: - ["Nemil Dalal", "https://www.nemil.com"] --- -Solidity is a statically typed, contract programming language for [Ethereum](https://www.ethereum.org/) that has similarities to Javascript and C. Like an object in object-oriented languages, each contract contains state variables, functions, and common data types. Contract-specific features include modifier (guard) clauses, event notifiers, and custom variables. +Solidity lets you program on [Ethereum](https://www.ethereum.org/), a blockchain-based virtual machine that allows the creation and computation of smart contracts, without needing centralized or trusted parties. -Solidity lets you program on Ethereum, a blockchain-based virtual machine that allows the creation and computation of smart contracts, without needing centralized or trusted parties. +Solidity is a statically typed, contract programming language that has similarities to Javascript and C. Like an object in object-oriented languages, each contract contains state variables, functions, and common data types. Contract-specific features include modifier (guard) clauses, event notifiers, and custom variables. As Solidity and Ethereum are under active development, experimental or beta features are explicitly marked, and subject to change. Pull requests welcome. @@ -46,7 +46,7 @@ contract AcmeBank { owner = msg.sender; // msg.sender refers to the address of the contract creator } - function deposit(uint balance) public { + function deposit(uint balance) public returns (uint) { balances[msg.sender] += msg.value; // no need for "this." or "self." in front of the state variable return balances[msg.sender]; // msg.sender refers to the contract caller @@ -65,7 +65,7 @@ contract AcmeBank { } // The 'constant' prevents the function from editing state variables - function balance() constant { + function balance() constant returns (uint) { return balances[msg.sender]; } @@ -90,6 +90,7 @@ uint x; // int of 256 bits, cannot be changed after instantiation int constant a = 8; int256 constant a = 8; // same effect as line above, here the 256 is explicit +uint constant VERSION_ID = 0x123A1; // A hex constant // For both int and uint, you can explicitly set space in steps of 8 // e.g., int8, int16 @@ -285,12 +286,14 @@ Coin.Sent().watch({}, '', function(error, result) { // The '_' (underscore) must be included as the last line in the function body, and is an indicator that the // function being called should be placed there -modifier onlyBefore(uint _time) { if (now >= _time) throw; _ } +modifier onlyAfter(uint _time) { if (now <= _time) throw; _ } +modifier onlyOwner { if (msg.sender == owner) _ } // You can then append it right after the function declaration function changeOwner(newOwner) - onlyBefore(someTime) - { +onlyAfter(someTime) +onlyOwner() +{ owner = newOwner; } @@ -298,7 +301,7 @@ function changeOwner(newOwner) // 5. BRANCHING AND LOOPS // All basic logic blocks work - including if/else, for, while, break, continue, return -// switch is not provided +// Unlike other languages, the 'switch' statement is NOT provided // Syntax is the same as javascript, but there is no type conversion from // non-boolean to boolean, so comparison operators must be used to get the boolean value @@ -377,7 +380,7 @@ if (!addr.send(123)) { // Suicide suicide(SOME_ADDRESS); // suicide the current contract, sending funds to the address (often the creator) -// This is a common pattern that lets the owner end the contract +// This is a common contract pattern that lets the owner end the contract, and receive remaining funds function remove() { if(msg.sender == owner) { // Only let the contract creator do this suicide(owner); // suicide makes this contract inactive, and returns funds to the owner @@ -391,7 +394,6 @@ function remove() { // planning your data structures) - // *** EXAMPLE: Let's do a more complex example *** // ** START EXAMPLE ** @@ -472,6 +474,7 @@ sha256("def"); - [Gitter Chat room](https://gitter.im/ethereum/go-ethereum) ## Sample contracts +- [Dapp Bin](https://github.com/ethereum/dapp-bin) - [Solidity Baby Step Contracts](https://github.com/fivedogit/solidity-baby-steps/tree/master/contracts) - [Consensys Contracts](https://github.com/ConsenSys/dapp-store-contracts) - [State of Dapps](http://dapps.ethercasts.com/) -- cgit v1.2.3 From 6749790c8d08aa5aaa06fd0501fd6bdd012ee29b Mon Sep 17 00:00:00 2001 From: Nemil Dalal Date: Mon, 28 Dec 2015 17:11:00 -0500 Subject: Many edits --- solidity.html.markdown | 739 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 499 insertions(+), 240 deletions(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index 7f925918..a6620986 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -5,134 +5,194 @@ contributors: - ["Nemil Dalal", "https://www.nemil.com"] --- -Solidity lets you program on [Ethereum](https://www.ethereum.org/), a blockchain-based virtual machine that allows the creation and computation of smart contracts, without needing centralized or trusted parties. +Solidity lets you program on [Ethereum](https://www.ethereum.org/), a +blockchain-based virtual machine that allows the creation and +computation of smart contracts, without needing centralized or trusted parties. -Solidity is a statically typed, contract programming language that has similarities to Javascript and C. Like an object in object-oriented languages, each contract contains state variables, functions, and common data types. Contract-specific features include modifier (guard) clauses, event notifiers, and custom variables. +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. -As Solidity and Ethereum are under active development, experimental or beta features are explicitly marked, and subject to change. Pull requests welcome. +Some Ethereum contract examples include crowdfunding, voting, and blind auctions. + +As Solidity and Ethereum are under active development, experimental or beta +features are explicitly marked, and subject to change. Pull requests welcome. ```javascript -// Let's start with a simple Bank contract, before diving into to the key components of the language -// This bank has three main capabilities: -// - deposit -// - withdrawal -// - check balance +// First, a simple Bank contract +// Allows deposits, withdrawals, and balance checks -// ** START EXAMPLE ** -// Start with a Natspec comment (the three slashes) that can be used -// for documentation - and as descriptive data for UI elements -/// @title A simple deposit/withdrawal bank built on Bitcoin - -// All contracts are declared and named (in CamelCase) -// They are similar to 'class' in other languages (and allow capabilities like inheritance) -contract AcmeBank { - // Declare state variables outside a function, - // these are persistent throughout the life of the contract - - // a dictionary that maps addresses to balances - // the private means that other contracts can't see balances - // but the data is still available to all other parties on the - // blockchain +// simple_bank.sol (note .sol extension) +/* **** START EXAMPLE **** */ + +// Start with Natspec comment (the three slashes) +// used for documentation - and as descriptive data for UI elements/actions + +/// @title SimpleBank +/// @author nemild + +/* 'contract' has similarities to 'class' in other languages (class variables, +inheritance, etc.) */ +contract SimpleBank { // CamelCase + // Declare state variables outside function, persist through life of contract + + // dictionary that maps addresses to balances mapping (address => uint) private balances; - // the 'public' makes 'owner' externally readable by users or contracts - // (but not writeable) + // "private" means that other contracts can't directly query balances + // but data is still viewable to other parties on blockchain + address public owner; + // 'public' makes externally readable (not writeable) by users or contracts - // Constructor, can receive one or many variables here + // Events - publicize actions to external listeners + event DepositMade(address accountAddress, uint amount); + + // Constructor, can receive one or many variables here; only one allowed function AcmeBank() { - // msg is a default variable that provides both the - // contract messager's address and amount - owner = msg.sender; // msg.sender refers to the address of the contract creator + // msg provides contract messager's address and amount + // msg.sender is contract caller (address of contract creator) + owner = msg.sender; } - function deposit(uint balance) public returns (uint) { - balances[msg.sender] += msg.value; // no need for "this." or "self." in front of the state variable + /// @notice Deposit ether into bank + /// @return The balance of the user after the deposit is made + function deposit() public returns (uint) { + balances[msg.sender] += msg.value; + // no "this." or "self." required with state variable + // all values initialized to 0 by default + + DepositMade(msg.sender, msg.value); // fire event - return balances[msg.sender]; // msg.sender refers to the contract caller + return balances[msg.sender]; } - function withdraw(uint withdrawAmount) public returns (uint remainingBalance) { - if(balances[msg.sender] >= withdrawAmount) { - balances[msg.sender] -= withdrawAmount; + /// @notice Withdraw ether from bank + /// @dev This does not return any excess ether sent to it + /// @param withdrawAmount amount you want to withdraw + /// @return The balance remaining for the user + function withdraw(uint withdrawAmount) public returns (uint remainingBal) { + if(balances[msg.sender] >= withdrawAmount) { + balances[msg.sender] -= withdrawAmount; if (!msg.sender.send(withdrawAmount)) { - balances[msg.sender] += withdrawAmount; + balances[msg.sender] += withdrawAmount; // to be safe } - return balances[msg.sender]; + return balances[msg.sender]; } } - // The 'constant' prevents the function from editing state variables + /// @notice Get balance + /// @return The balance of the user + // 'constant' prevents function from editing state variables; + // allows function to run locally/off blockchain function balance() constant returns (uint) { - return balances[msg.sender]; + return balances[msg.sender]; } - // Fallback function - // The fallback function is called if none of the other functions matches the given function identifier. - // Typically, called when invalid data is sent to the contract or ether without data. - // Added so that ether sent to this contract is reverted if the contract fails - // otherwise, the sender loses their money; you should add this in most contracts - function () { throw; } + // Fallback function - Called if other functions don't match call or + // sent ether without data + // Typically, called when invalid data is sent + // Added so ether sent to this contract is reverted if the contract fails + // otherwise, the sender's money is transferred to contract + function () { + throw; // throw reverts state to before call + } } // ** END EXAMPLE ** -// Now let's go through the basics of Solidity +// Now, the basics of Solidity // 1. DATA TYPES AND ASSOCIATED METHODS -// uint is the data type typically used for currency (there are no doubles -// or floats) and for dates +// uint used for currency amount (there are no doubles +// or floats) and for dates (in unix time) uint x; -// with 'constant', the compiler replaces each occurrence with the actual value // int of 256 bits, cannot be changed after instantiation int constant a = 8; + +// with 'constant', compiler replaces each occurrence with actual value int256 constant a = 8; // same effect as line above, here the 256 is explicit uint constant VERSION_ID = 0x123A1; // A hex constant -// For both int and uint, you can explicitly set space in steps of 8 -// e.g., int8, int16 +// Be careful that you don't overflow, and protect against attacks that do + +// For int and uint, can explicitly set space in steps of 8 up to 256 +// e.g., int8, int16, int24 uint8 b; int64 c; uint248 e; +// No random functions built in, use other contracts for randomness + // Type casting int x = int(b); bool b = true; // or do 'var b = true;' for inferred typing -// Addresses - holds 20 byte/160 bit Ethereum addresses to another contract -// ('Contract Account)') or person/external entity ('External Account') -address public owner; // Add 'public' field to indicate publicly/externally accessible, a getter is automatically created, but NOT a setter +// Addresses - holds 20 byte/160 bit Ethereum addresses +// No arithmetic allowed +address public owner; -// All addresses can be sent ether in the following way: +// Types of accounts: +// Contract account: address set on create (func of creator address, num transactions sent) +// External Account: (person/external entity): address created from public key + +// Add 'public' field to indicate publicly/externally accessible +// a getter is automatically created, but NOT a setter + +// All addresses can be sent ether owner.send(SOME_BALANCE); // returns false on failure -owner.balance; // the balance of the owner +if (owner.send) {} // typically wrap in 'if', as contract addresses have +// functions have executed on send and can fail + +// can override send by defining your own -// Bytes are provided from 1 to 32 +// Can check balance +owner.balance; // the balance of the owner (user or contract) + + +// Bytes available from 1 to 32 byte a; // byte is same as bytes1 -bytes32 b; +bytes2 b; +bytes32 c; + +// Dynamically sized bytes +bytes m; // A special array, same as byte[] array (but packed tightly) +// More expensive than byte1-byte32, so use those when possible -// Dynamically sized -bytes m; // A special array, same as byte[] (but packed tightly) // same as bytes, but does not allow length or index access (for now) -string n = 'hello'; +string n = "hello"; // stored in UTF8, note double quotes, not single +// string utility functions to be added in future +// prefer bytes32/bytes, as UTF8 uses more storage -// Type inference +// Type inferrence // var does inferred typing based on first assignment, // can't be used in functions parameters var a = true; -// there are edge cases where inference leads to a value being set (e.g., an uint 8) -// that is different from what the user wanted (uint16), so use carefully +// use carefully, inference may provide wrong type +// e.g., an int8, when a counter needs to be int16 + +// var can be used to assign function to variable +function a(uint x) returns (uint) { + return x * 2; +} +var f = a; +f(22); // call // by default, all values are set to 0 on instantiation // Delete can be called on most types -// (it does NOT destroy the value, but rather sets the value to 0 by assignment) +// (does NOT destroy value, but sets value to 0, the initial value) uint x = 5; -delete x; // x is now 0 + + +// Destructuring/Tuples +(x, y) = (2, 7); // assign/swap multiple value // 2. DATA STRUCTURES @@ -142,74 +202,97 @@ bytes32[] names; // dynamic array uint newLength = names.push("John"); // adding returns new length of the array // Length names.length; // get length -names.length = 1; // lengths can also be set, unlike many other languages +names.length = 1; // lengths can be set (for dynamic arrays in storage only) + +// multidimensional array +uint x[][5]; // arr with 5 dynamic array elements (opp order of most languages) // Dictionaries (any type to any other type) mapping (string => uint) public balances; -balances["john"] = 1; -console.log(balances[jill]); // is 0, all non-set key values return zeroes -// The 'public' lets you do the following from another contract -contractName.balances("john"); // returns 1 -// The 'public' keyword here created a getter (but not setter) that behaves like the following: +balances["charles"] = 1; +console.log(balances["ada"]); // is 0, all non-set key values return zeroes +// 'public' allows following from another contract +contractName.balances("claude"); // returns 1 +// 'public' created a getter (but not setter) like the following: function balances(address _account) returns (uint balance) { - return balances[_account]; + return balances[_account]; } +// Nested mappings +mapping (address => mapping (address => uint) balances) public custodians; + // To delete delete balances["John"]; -delete balances; // deletes all elements +delete balances; // sets all elements to 0 -// Unlike languages like Javascript, you cannot iterate through all elements in -// a map, without knowing the source keys +// Unlike other languages, CANNOT iterate through all elements in +// mapping, without knowing source keys - can build data structure +// on top to do this // Structs and enums - struct Bank { // note the capital - address owner; - uint balance; - } +struct Bank { + address owner; + uint balance; +} Bank b = Bank({ - owner: msg.sender, - balance: 5 + owner: msg.sender, + balance: 5 }); -delete b; // set all variables in struct to 0, except any mappings +// or +Bank c = Bank(msg.sender, 5); + +c.amount = 5; // set to new value +delete b; +// sets to initial value, set all variables in struct to 0, except mappings // Enums -enum State { Created, Locked, Inactive }; +enum State { Created, Locked, Inactive }; // often used for state machine State public state; // Declare variable from enum state = State.Created; // enums can be explicitly converted to ints +uint createdState = uint(State.Created); // 0 -// Data locations: Memory vs. storage - all complex types (arrays, structs) have a data location +// Data locations: Memory vs. storage vs. stack - all complex types (arrays, +// structs) have a data location // 'memory' does not persist, 'storage' does -// Default is 'storage' for local and state variables; 'memory' for function parameters +// Default is 'storage' for local and state variables; 'memory' for func params +// stack holds small local variables + +// for most types, can explicitly set which data location to use + +// 3. Simple operators +// Comparisons, bit operators and arithmetic operators are provided +// exponentiation: ** +// exclusive or: ^ +// bitwise negation: ~ -// 3. Variables of note + +// 4. Global Variables of note // ** this ** -this; // the address of the current contract -// 'balance' often used at the end of a contracts life to send the -// remaining balance to a party +this; // address of contract +// often used at end of contract life to send remaining balance to party this.balance; -this.someFunction(); // calls a function externally (via a message call, not via an internal jump) +this.someFunction(); // calls func externally via call, not via internal jump -// ** msg - The current message received by the contract ** ** -msg.sender; // address, The address of the sender -msg.value; // uint, The amount of gas provided to this contract in wei +// ** msg - Current message received by the contract ** ** +msg.sender; // address of sender +msg.value; // amount of gas provided to this contract in wei msg.data; // bytes, complete call data msg.gas; // remaining gas // ** tx - This transaction ** -tx.origin; // address, sender of the transaction -tx.gasprice; // uint, gas price of the transaction - -// ** block - Information about the current block ** -now // uint, current time, alias for block.timestamp -block.number; // uint, current block number -block.difficulty; // uint, current block difficulty -block.blockhash(1); // returns bytes32, only provides for most recent 256 blocks +tx.origin; // address of sender of the transaction +tx.gasprice; // gas price of the transaction + +// ** block - Information about current block ** +now // current time (approximately), alias for block.timestamp (uses Unix time) +block.number; // current block number +block.difficulty; // current block difficulty +block.blockhash(1); // returns bytes32, only works for most recent 256 blocks block.gasLimit(); -// ** storage - A persistent storage hash (does not need to be declared) ** +// ** storage - Persistent storage hash ** storage['abc'] = 'def'; // maps 256 bit words to 256 bit words @@ -217,55 +300,61 @@ storage['abc'] = 'def'; // maps 256 bit words to 256 bit words // A. Functions // Simple function function increment(uint x) returns (uint) { - x += 1; - return x; + x += 1; + return x; } -// Functions can return many arguments, and by specifying the returned arguments -// you don't need to explicitly return +// Functions can return many arguments, and by specifying returned arguments +// name don't need to explicitly return function increment(uint x, uint y) returns (uint x, uint y) { - x += 1; - y += 1; + x += 1; + y += 1; } -// This function would have been called like this, and assigned to a tuple +// Call previous functon uint (a,b) = increment(1,1); -// The 'constant' indicates and ensures that a function does not/cannot change the persistent variables -// Constant function execute locally, not on the blockchain +// 'constant' indicates that function does not/cannot change persistent vars +// Constant function execute locally, not on blockchain uint y; function increment(uint x) constant returns (uint x) { - x += 1; - y += 1; // this line would fail - // as y is a state variable, and can't be changed in a constant function + x += 1; + y += 1; // this line would fail + // y is a state variable, and can't be changed in a constant function } -// There are a few 'function visibility specifiers' that can be placed where 'constant' -// is, which include: -// internal (can only be called by an internal function, not one external to the contract) -// public - visible externally and internally +// 'Function Visibility specifiers' +// These can be placed where 'constant' is, including: +// public - visible externally and internally (default) +// external // private - only visible in the current contract +// internal - only visible in current contract, and those deriving from it -// Functions are hoisted (so you can call a function, even if it is declared later) - and you can assign a function to a variable +// Functions hoisted - and can assign a function to a variable function a() { - var z = b; - b(); + var z = b; + b(); } function b() { } + +// Prefer loops to recursion (max call stack depth is 1024) + // B. Events -// Events are an easy way to notify external listeners that something changed -// You typically declare them after your contract parameters -event Sent(address from, address to, uint amount); +// Events are notify external parties; easy to search and +// access events from outside blockchain (with lightweight clients) +// typically declare after contract parameters -// You then call it in a function, when you want to trigger it -sent(from, to, amount); +// Declare +event Sent(address from, address to, uint amount); // note capital first letter -// For an external party (a contract or external entity), to watch -// for an event, you write the following: +// Call +Sent(from, to, amount); + +// For an external party (a contract or external entity), to watch: Coin.Sent().watch({}, '', function(error, result) { if (!error) { console.log("Coin transfer: " + result.args.amount + @@ -276,195 +365,356 @@ Coin.Sent().watch({}, '', function(error, result) { "Receiver: " + Coin.balances.call(result.args.to)); } } -// This is a common paradigm for one contract to depend on another (e.g., a -// contract that depends on the current exchange rate provided by another -// contract) +// Common paradigm for one contract to depend on another (e.g., a +// contract that depends on current exchange rate provided by another) // C. Modifiers -// Modifiers let you validate inputs to functions such as a minimal balance or user authentication -// It's similar to a guard clause in other languages +// Modifiers validate inputs to functions such as minimal balance or user auth; +// similar to guard clause in other languages -// The '_' (underscore) must be included as the last line in the function body, and is an indicator that the +// '_' (underscore) often included as last line in body, and indicates // function being called should be placed there modifier onlyAfter(uint _time) { if (now <= _time) throw; _ } modifier onlyOwner { if (msg.sender == owner) _ } +// commonly used with state machines +modifier onlyIfState (State currState) { if (currState != State.A) _ } -// You can then append it right after the function declaration +// Append right after function declaration function changeOwner(newOwner) onlyAfter(someTime) onlyOwner() +onlyIfState(State.A) { - owner = newOwner; + owner = newOwner; } +// underscore can be included before end of body, +// but explicitly returning will skip, so use carefully +modifier checkValue(uint amount) { + _ + if (msg.value > amount) { + msg.sender.send(amount - msg.value); + } +} -// 5. BRANCHING AND LOOPS -// All basic logic blocks work - including if/else, for, while, break, continue, return -// Unlike other languages, the 'switch' statement is NOT provided +// 6. BRANCHING AND LOOPS -// Syntax is the same as javascript, but there is no type conversion from -// non-boolean to boolean, so comparison operators must be used to get the boolean value +// All basic logic blocks work - including if/else, for, while, break, continue +// return - but no switch +// Syntax same as javascript, but no type conversion from non-boolean +// to boolean (comparison operators must be used to get the boolean val) -// 6. OBJECTS/CONTRACTS -// A. Calling an external contract +// 7. OBJECTS/CONTRACTS + +// A. Calling external contract contract infoFeed { - function info() returns (uint ret) { return 42; } + function info() returns (uint ret) { return 42; } } contract Consumer { - InfoFeed feed; // create a variable that will point to a contract on the blockchain - - // Set feed to an existing contract - function setFeed(address addr) { - // Link to the contract by creating on the address - feed = InfoFeed(addr); - } - - // Set feed based to a new instance of the contract - function createNewFeed() { - feed = new InfoFeed(); - } - - function callFeed() { - // T final parentheses call the contract, optionally adding - // custom value or gas numbers - feed.info.value(10).gas(800)(); - } + InfoFeed feed; // points to contract on blockchain + + // Set feed to existing contract instance + function setFeed(address addr) { + // automatically cast, be careful; constructor is not called + feed = InfoFeed(addr); + } + + // Set feed to new instance of contract + function createNewFeed() { + feed = new InfoFeed(); // constructor called + } + + function callFeed() { + // final parentheses call contract, can optionally add + // custom ether value or gas + feed.info.value(10).gas(800)(); + } } // B. Inheritance -// Order matters, last inherited contract (i.e., 'def') can override parts of the previously -// inherited contracts -contact MyContract is abc, def("a custom argument to def") { +// Order matters, last inherited contract (i.e., 'def') can override parts of +// previously inherited contracts +contract MyContract is abc, def("a custom argument to def") { // Override function - - function z() { - if (msg.sender == owner) { - def.z(); // call overridden function + function z() { + if (msg.sender == owner) { + def.z(); // call overridden function from def + super.z(); // call immediate parent overriden function + } } - } +} - }; +// abstract function +function someAbstractFunction(uint x); +// cannot be compiled, so used in base/abstract contracts +// that are then implemented // C. Import import "filename"; import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol"; -// Importing is under active development and will change -// Importing cannot currently be done at the command line - - -// 7. CONTRACT DESIGN PATTERNS +// Importing under active development +// Cannot currently be done at command line -// A. Obfuscation -// Remember that all variables are publicly viewable on the blockchain, so -// anything that needs some privacy needs to be obfuscated (e.g., hashed) +// 8. OTHER KEYWORDS -// B. Throwing +// A. Throwing // Throwing -throw; // throwing is easily done, and reverts unused money to the sender -// You can't currently catch +throw; // reverts unused money to sender, state is reverted +// Can't currently catch -// A common design pattern is: +// Common design pattern is: if (!addr.send(123)) { - throw; + throw; } -// C. Suicide -// Suicide -suicide(SOME_ADDRESS); // suicide the current contract, sending funds to the address (often the creator) +// B. Selfdestruct +// selfdestruct current contract, sending funds to address (often creator) +selfdestruct(SOME_ADDRESS); + +// removes storage/code from current/future blocks +// helps thin clients, but previous data persists in blockchain -// This is a common contract pattern that lets the owner end the contract, and receive remaining funds +// Common pattern, lets owner end the contract and receive remaining funds function remove() { - if(msg.sender == owner) { // Only let the contract creator do this - suicide(owner); // suicide makes this contract inactive, and returns funds to the owner - } + if(msg.sender == creator) { // Only let the contract creator do this + selfdestruct(creator); // Makes contract inactive, returns funds + } } -// D. Storage optimization -// Reading and writing can be expensive, as data needs to be stored in the -// blockchain forever - this encourages smart ways to use memory (eventually, -// compilation may better handle this, but for now there are benefits to -// planning your data structures) +// May want to deactivate contract manually, rather than selfdestruct +// (ether sent to selfdestructed contract is lost) + + +// 9. CONTRACT DESIGN NOTES + +// A. Obfuscation +// Remember all variables are publicly viewable on blockchain, so +// anything that needs privacy needs to be obfuscated (e.g., hashed) + +// Steps: 1. Commit to something, 2. Reveal commitment +sha3("some_bid_amount", "some secret"); // commit + +// call contract's reveal function showing bid plus secret that hashes to SHA3 +reveal(100, "mySecret"); + +// B. Storage optimization +// Writing to blockchain can be expensive, as data stored forever encourages +// smart ways to use memory (eventually, compilation will be better, but for now +// benefits to planning data structures - and storing min amount in blockchain) + +// Cost can often be high for items like multidimensional arrays +// (cost is for storing data - not declaring unfilled variables) + +// C. Cannot restrict human or computer from reading contents of +// transaction or transaction's state + +// When 'private' specified, indicating that other *contracts* can't read +// the data directly - any other party can still read the data in blockchain +// D. All data to start of time is stored in blockchain, so +// anyone can observe all previous data and changes -// *** EXAMPLE: Let's do a more complex example *** +// E. Cron +// Contracts must be manually called to handle time-based scheduling; can create +// external code to do, or provide incentives (ether) for others to do for you +// F. State machines +// see example below for State enum and inState modifier + +// *** EXAMPLE: A crowdfunding example (broadly similar to Kickstarter) *** // ** START EXAMPLE ** -// [TODO: Decide what a more complex example looks like, needs a few characteristics: -// - has a 'constant' state variable -// - has a state machine (and uses modifier) -// - sends money to an address -// - gets information from another contract (we'll show code for both contracts) -// - Shows inheritance -// - show variables being passed in on instantiation (and guard code to throw if variables not provided) -// - Shows the swapping out of a contract address -// Ideas: -// - crowdfunding? -// - Peer to peer insurance -// ] - // It's good practice to have a remove function, which disables this - // contract - but does mean that users have to trust the owner - // For a decentralized bank without a trusted part - function remove() { - if(msg.sender == owner) { // Only let the contract creator do this - suicide(owner); // suicide makes this contract inactive, and returns funds to the owner - } + +// CrowdFunder.sol + +/// @title CrowdFunder +/// @author nemild +contract CrowdFunder { + // Variables set on create by creator + address public creator; + address public fundRecipient; // creator may be different than recipient + uint public minimumToRaise; // required to tip, else everyone gets refund + string campaignUrl; + + // Data structures + enum State { + Fundraising, + ExpiredRefundPending, + Successful, + ExpiredRefundComplete + } + struct Contribution { + uint amount; + address contributor; } -// *** END EXAMPLE *** + // State variables + State public state = State.Fundraising; // initialize on create + uint public totalRaised; + uint public raiseBy; + Contribution[] contributions; + + event fundingReceived(address addr, uint amount, uint currentTotal); + event allRefundsSent(); + event winnerPaid(address winnerAddress); + + modifier inState(State _state) { + if (state != _state) throw; + _ + } -// 7. NATIVE FUNCTIONS + modifier isCreator() { + if (msg.sender != creator) throw; + _ + } + + modifier atEndOfLifecycle() { + if(state != State.ExpiredRefundComplete && state != State.Successful) { + throw; + } + } + + function CrowdFunder( + uint timeInHoursForFundraising, + string _campaignUrl, + address _fundRecipient, + uint _minimumToRaise) + { + creator = msg.sender; + fundRecipient = _fundRecipient; + campaignUrl = _campaignUrl; + minimumToRaise = _minimumToRaise; + raiseBy = now + (timeInHoursForFundraising * 1 hours); + } + + function contribute() + public + inState(State.Fundraising) + { + contributions.push( + Contribution({ + amount: msg.value, + contributor: msg.sender + }) // use array, so can iterate + ); + totalRaised += msg.value; + + fundingReceived(msg.sender, msg.value, totalRaised); + + checkIfFundingCompleteOrExpired(); + } + + function checkIfFundingCompleteOrExpired() { + if (totalRaised > minimumToRaise) { + state = State.Successful; + payOut(); + + // could incentivize sender who initiated state change here + } else if ( now > raiseBy ) { + state = State.ExpiredRefundPending; + refundAll(); + } + } + + function payOut() + public + inState(State.Successful) + { + if(!fundRecipient.send(this.balance)) { + throw; + } + + winnerPaid(fundRecipient); + } + + function refundAll() + public + inState(State.ExpiredRefundPending) + { + uint length = contributions.length; + for (uint i = 0; i < length; i++) { + if(!contributions[i].contributor.send(contributions[i].amount)) { + throw; + } + } + + allRefundsSent(); + state = State.ExpiredRefundComplete; + } + + function removeContract() + public + isCreator() + atEndOfLifecycle() + { + selfdestruct(msg.sender); + } + + function () { throw; } +} +// ** END EXAMPLE ** + +// 10. OTHER NATIVE FUNCTIONS // Currency units -// By default, currency is defined using wei, the smallest unit of Ether +// Currency is defined using wei, smallest unit of Ether uint minAmount = 1 wei; -uint a = 1 finney; // 1 ether = 1000 finney -// There are a number of other units, see: http://ether.fund/tool/converter +uint a = 1 finney; // 1 ether == 1000 finney +// Other units, see: http://ether.fund/tool/converter // Time units 1 == 1 second 1 minutes == 60 seconds - -// You typically multiply a variable times the unit, as these units are not -// directly stored in a variable +// Can multiply a variable times unit, as units are not stored in a variable uint x = 5; (x * 1 days); // 5 days -// Be careful about leap seconds and leap years when using equality statements for time (instead, prefer greater than/less than) +// Careful about leap seconds/years with equality statements for time +// (instead, prefer greater than/less than) // Cryptography -// All strings passed are concatenated before the hash is run +// All strings passed are concatenated before hash action sha3("ab", "cd"); ripemd160("abc"); sha256("def"); +11. LOW LEVEL FUNCTIONS +// call - low level, not often used, does not provide type safety +successBoolean = someContractAddress.call('function_name', 'arg1', 'arg2'); -// 8. COMMON MISTAKES/MISCONCEPTIONS -// A few common mistakes and misconceptions: +// callcode - Code at target address executed in *context* of calling contract +// provides library functionality +someContractAddress.callcode('function_name'); -// A. You cannot restrict a human or computer from reading the content of -// your transaction or a transaction's state +// 12. STYLE NOTES +// Based on Python's PEP8 style guide -// All data to the start of time is stored in the blockchain, so you and -// anyone can observe all previous data stats +// 4 spaces for indentation +// Two lines separate contract declarations (and other top level declarations) +// Avoid extraneous spaces in parentheses +// Can omit curly braces for one line statement (if, for, etc) +// else should be placed on own line -// When you don't specify public on a variable, you are indicating that other *contracts* can't -// read the data - but any person can still read the data +// 13. NATSPEC comments - used for documentation, commenting, and external UIs +// Contract natspec - always above contract definition +/// @title Contract title +/// @author Author name -// TODO +// Function natspec +/// @notice information about what function does; shown when function to execute +/// @dev Function documentation for developer - -// 9. STYLE NOTES -// Use 4 spaces for indentation -// (Python's PEP8 is used as the baseline style guide, including its general philosophy) +// Function parameter/return value natspec +/// @param someParam Some description of what the param does +/// @return Description of the return value ``` ## Additional resources @@ -472,6 +722,8 @@ sha256("def"); - [Solidity Style Guide](https://ethereum.github.io/solidity//docs/style-guide/): Ethereum's style guide is heavily derived from Python's [pep8](https://www.python.org/dev/peps/pep-0008/) style guide. - [Browser-based Solidity Editor](http://chriseth.github.io/browser-solidity/) - [Gitter Chat room](https://gitter.im/ethereum/go-ethereum) +- [Modular design strategies for Ethereum Contracts](https://docs.erisindustries.com/tutorials/solidity/) +- Editor Snippets ([Ultisnips format](https://gist.github.com/nemild/98343ce6b16b747788bc)) ## Sample contracts - [Dapp Bin](https://github.com/ethereum/dapp-bin) @@ -481,5 +733,12 @@ sha256("def"); ## Information purposefully excluded - Libraries +- [Call keyword](http://solidity.readthedocs.org/en/latest/types.html) + +## Style +- Python's [PEP8](https://www.python.org/dev/peps/pep-0008/) is used as the baseline style guide, including its general philosophy) + +## Future To Dos +- New keywords: protected, inheritable Feel free to send a pull request with any edits - or email nemild -/at-/ gmail -- cgit v1.2.3 From 8f9f9e53e825b346c49139769b8bbfd08d0bed4e Mon Sep 17 00:00:00 2001 From: Nemil Dalal Date: Mon, 28 Dec 2015 17:13:20 -0500 Subject: Spacing --- solidity.html.markdown | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index a6620986..7de92fce 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -463,6 +463,7 @@ import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol"; // Importing under active development // Cannot currently be done at command line + // 8. OTHER KEYWORDS // A. Throwing @@ -529,6 +530,7 @@ reveal(100, "mySecret"); // F. State machines // see example below for State enum and inState modifier + // *** EXAMPLE: A crowdfunding example (broadly similar to Kickstarter) *** // ** START EXAMPLE ** @@ -661,6 +663,7 @@ contract CrowdFunder { } // ** END EXAMPLE ** + // 10. OTHER NATIVE FUNCTIONS // Currency units @@ -686,7 +689,8 @@ sha3("ab", "cd"); ripemd160("abc"); sha256("def"); -11. LOW LEVEL FUNCTIONS + +// 11. LOW LEVEL FUNCTIONS // call - low level, not often used, does not provide type safety successBoolean = someContractAddress.call('function_name', 'arg1', 'arg2'); @@ -694,6 +698,7 @@ successBoolean = someContractAddress.call('function_name', 'arg1', 'arg2'); // provides library functionality someContractAddress.callcode('function_name'); + // 12. STYLE NOTES // Based on Python's PEP8 style guide @@ -703,6 +708,7 @@ someContractAddress.callcode('function_name'); // Can omit curly braces for one line statement (if, for, etc) // else should be placed on own line + // 13. NATSPEC comments - used for documentation, commenting, and external UIs // Contract natspec - always above contract definition /// @title Contract title -- cgit v1.2.3 From 43138aef5cc6a89ec0c02db03cec61ab902acb97 Mon Sep 17 00:00:00 2001 From: ethers Date: Mon, 28 Dec 2015 16:36:48 -0800 Subject: fixes in withdraw() and msg --- solidity.html.markdown | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index 7de92fce..146d6e83 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -7,7 +7,7 @@ contributors: Solidity lets you program on [Ethereum](https://www.ethereum.org/), a blockchain-based virtual machine that allows the creation and -computation of smart contracts, without needing centralized or trusted parties. +execution of smart contracts, without needing 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 @@ -52,7 +52,7 @@ contract SimpleBank { // CamelCase // Constructor, can receive one or many variables here; only one allowed function AcmeBank() { - // msg provides contract messager's address and amount + // msg provides details about the message that's sent to the contract // msg.sender is contract caller (address of contract creator) owner = msg.sender; } @@ -77,12 +77,12 @@ contract SimpleBank { // CamelCase if(balances[msg.sender] >= withdrawAmount) { balances[msg.sender] -= withdrawAmount; - if (!msg.sender.send(withdrawAmount)) { - balances[msg.sender] += withdrawAmount; // to be safe + if (!msg.sender.send(withdrawAmount)) { + balances[msg.sender] += withdrawAmount; // to be safe + } } - - return balances[msg.sender]; - } + + return balances[msg.sender]; } /// @notice Get balance @@ -277,7 +277,7 @@ this.someFunction(); // calls func externally via call, not via internal jump // ** msg - Current message received by the contract ** ** msg.sender; // address of sender -msg.value; // amount of gas provided to this contract in wei +msg.value; // amount of ether provided to this contract in wei msg.data; // bytes, complete call data msg.gas; // remaining gas -- cgit v1.2.3 From 65cba2b1f5405d53e498bfa96a0e407423dd9a4e Mon Sep 17 00:00:00 2001 From: Nemil Dalal Date: Mon, 28 Dec 2015 21:53:37 -0500 Subject: Fixed mapping --- solidity.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index 7de92fce..5b632c11 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -219,7 +219,7 @@ function balances(address _account) returns (uint balance) { } // Nested mappings -mapping (address => mapping (address => uint) balances) public custodians; +mapping (address => mapping (address => uint)) public custodians; // To delete delete balances["John"]; -- cgit v1.2.3 From ba3d5a6feb4a340c43b55b75516fed1d78fad9fb Mon Sep 17 00:00:00 2001 From: Nemil Dalal Date: Mon, 28 Dec 2015 21:58:31 -0500 Subject: Added Joseph Chow as contributor --- solidity.html.markdown | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index 2d653bf9..b73ca0e5 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -2,7 +2,8 @@ language: Solidity filename: learnSolidity.sol contributors: - - ["Nemil Dalal", "https://www.nemil.com"] + - ["Nemil Dalal", "https://www.nemil.com"] + - ["Joseph Chow", ""] --- Solidity lets you program on [Ethereum](https://www.ethereum.org/), a @@ -81,7 +82,7 @@ contract SimpleBank { // CamelCase balances[msg.sender] += withdrawAmount; // to be safe } } - + return balances[msg.sender]; } -- cgit v1.2.3 From 58ebc87f5f4114c3610633a7cd9c4264647b2448 Mon Sep 17 00:00:00 2001 From: Nemil Dalal Date: Mon, 28 Dec 2015 22:29:19 -0500 Subject: Minor edits --- solidity.html.markdown | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index b73ca0e5..5946c1f5 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -79,7 +79,9 @@ contract SimpleBank { // CamelCase balances[msg.sender] -= withdrawAmount; if (!msg.sender.send(withdrawAmount)) { - balances[msg.sender] += withdrawAmount; // to be safe + // to be safe, may be sending to contract that + // has overridden 'send' which may then fail + balances[msg.sender] += withdrawAmount; } } @@ -710,7 +712,9 @@ someContractAddress.callcode('function_name'); // else should be placed on own line -// 13. NATSPEC comments - used for documentation, commenting, and external UIs +// 13. NATSPEC COMENTS +// used for documentation, commenting, and external UIs + // Contract natspec - always above contract definition /// @title Contract title /// @author Author name @@ -740,7 +744,6 @@ someContractAddress.callcode('function_name'); ## Information purposefully excluded - Libraries -- [Call keyword](http://solidity.readthedocs.org/en/latest/types.html) ## Style - Python's [PEP8](https://www.python.org/dev/peps/pep-0008/) is used as the baseline style guide, including its general philosophy) -- cgit v1.2.3 From bdd8a8b0c87d58332f39facc60d6ab7d576764df Mon Sep 17 00:00:00 2001 From: Nemil Dalal Date: Mon, 28 Dec 2015 22:31:48 -0500 Subject: Wording --- solidity.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index 5946c1f5..ebc58491 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -500,8 +500,8 @@ function remove() { // 9. CONTRACT DESIGN NOTES // A. Obfuscation -// Remember all variables are publicly viewable on blockchain, so -// anything that needs privacy needs to be obfuscated (e.g., hashed) +// All variables are publicly viewable on blockchain, so anything +// that should be totally private needs to be obfuscated (e.g., hashed w/secret) // Steps: 1. Commit to something, 2. Reveal commitment sha3("some_bid_amount", "some secret"); // commit -- cgit v1.2.3 From 24740321f478c25bb1dc651f6c95e11525a16781 Mon Sep 17 00:00:00 2001 From: ethers Date: Mon, 28 Dec 2015 23:45:58 -0800 Subject: update links to docs and Gitter --- solidity.html.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index ebc58491..911aca92 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -729,17 +729,17 @@ someContractAddress.callcode('function_name'); ``` ## Additional resources -- [Solidity Docs](https://ethereum.github.io/solidity/docs/home/) +- [Solidity Docs](https://solidity.readthedocs.org/en/latest/) - [Solidity Style Guide](https://ethereum.github.io/solidity//docs/style-guide/): Ethereum's style guide is heavily derived from Python's [pep8](https://www.python.org/dev/peps/pep-0008/) style guide. - [Browser-based Solidity Editor](http://chriseth.github.io/browser-solidity/) -- [Gitter Chat room](https://gitter.im/ethereum/go-ethereum) +- [Gitter Chat room](https://gitter.im/ethereum/solidity) - [Modular design strategies for Ethereum Contracts](https://docs.erisindustries.com/tutorials/solidity/) - Editor Snippets ([Ultisnips format](https://gist.github.com/nemild/98343ce6b16b747788bc)) ## Sample contracts - [Dapp Bin](https://github.com/ethereum/dapp-bin) - [Solidity Baby Step Contracts](https://github.com/fivedogit/solidity-baby-steps/tree/master/contracts) -- [Consensys Contracts](https://github.com/ConsenSys/dapp-store-contracts) +- [ConsenSys Contracts](https://github.com/ConsenSys/dapp-store-contracts) - [State of Dapps](http://dapps.ethercasts.com/) ## Information purposefully excluded -- cgit v1.2.3 From fc528c92ddbdca1d0cb3a5c8f3ad477fbc115ad9 Mon Sep 17 00:00:00 2001 From: Nemil Dalal Date: Tue, 29 Dec 2015 10:59:01 -0500 Subject: Cleaned up data types --- solidity.html.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index ebc58491..d84b6a68 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -117,12 +117,10 @@ uint x; // int of 256 bits, cannot be changed after instantiation int constant a = 8; - -// with 'constant', compiler replaces each occurrence with actual value int256 constant a = 8; // same effect as line above, here the 256 is explicit uint constant VERSION_ID = 0x123A1; // A hex constant +// with 'constant', compiler replaces each occurrence with actual value -// Be careful that you don't overflow, and protect against attacks that do // For int and uint, can explicitly set space in steps of 8 up to 256 // e.g., int8, int16, int24 @@ -130,6 +128,8 @@ uint8 b; int64 c; uint248 e; +// Be careful that you don't overflow, and protect against attacks that do + // No random functions built in, use other contracts for randomness // Type casting -- cgit v1.2.3 From 7e4a42d0b8cec4c0e2a6b90ad261c7755afe1136 Mon Sep 17 00:00:00 2001 From: Nemil Dalal Date: Tue, 29 Dec 2015 11:10:39 -0500 Subject: Reorganizing later sections --- solidity.html.markdown | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index 8c416be3..6705dde9 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -501,7 +501,7 @@ function remove() { // A. Obfuscation // All variables are publicly viewable on blockchain, so anything -// that should be totally private needs to be obfuscated (e.g., hashed w/secret) +// that is private needs to be obfuscated (e.g., hashed w/secret) // Steps: 1. Commit to something, 2. Reveal commitment sha3("some_bid_amount", "some secret"); // commit @@ -510,27 +510,28 @@ sha3("some_bid_amount", "some secret"); // commit reveal(100, "mySecret"); // B. Storage optimization -// Writing to blockchain can be expensive, as data stored forever encourages +// Writing to blockchain can be expensive, as data stored forever; encourages // smart ways to use memory (eventually, compilation will be better, but for now // benefits to planning data structures - and storing min amount in blockchain) // Cost can often be high for items like multidimensional arrays // (cost is for storing data - not declaring unfilled variables) -// C. Cannot restrict human or computer from reading contents of +// C. Data access in blockchain +// Cannot restrict human or computer from reading contents of // transaction or transaction's state -// When 'private' specified, indicating that other *contracts* can't read -// the data directly - any other party can still read the data in blockchain +// While 'private' prevents other *contracts* from reading data +// directly - any other party can still read data in blockchain -// D. All data to start of time is stored in blockchain, so +// All data to start of time is stored in blockchain, so // anyone can observe all previous data and changes -// E. Cron -// Contracts must be manually called to handle time-based scheduling; can create -// external code to do, or provide incentives (ether) for others to do for you +// D. Cron Job +// Contracts must be manually called to handle time-based scheduling; can create external +// code to regularly ping, or provide incentives (ether) for others to -// F. State machines +// E. State machines // see example below for State enum and inState modifier @@ -705,6 +706,7 @@ someContractAddress.callcode('function_name'); // 12. STYLE NOTES // Based on Python's PEP8 style guide +// Quick summary: // 4 spaces for indentation // Two lines separate contract declarations (and other top level declarations) // Avoid extraneous spaces in parentheses -- cgit v1.2.3 From d97c7be291b6bc3fb1477c30ac96b5b6cc36b9c4 Mon Sep 17 00:00:00 2001 From: Nemil Dalal Date: Tue, 29 Dec 2015 13:05:45 -0500 Subject: Minor wording changes, typos --- solidity.html.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index 6705dde9..71a44b92 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -63,7 +63,7 @@ contract SimpleBank { // CamelCase function deposit() public returns (uint) { balances[msg.sender] += msg.value; // no "this." or "self." required with state variable - // all values initialized to 0 by default + // all values set to data type's initial value by default DepositMade(msg.sender, msg.value); // fire event @@ -289,7 +289,7 @@ tx.origin; // address of sender of the transaction tx.gasprice; // gas price of the transaction // ** block - Information about current block ** -now // current time (approximately), alias for block.timestamp (uses Unix time) +now; // current time (approximately), alias for block.timestamp (uses Unix time) block.number; // current block number block.difficulty; // current block difficulty block.blockhash(1); // returns bytes32, only works for most recent 256 blocks @@ -428,7 +428,7 @@ contract Consumer { // Set feed to new instance of contract function createNewFeed() { - feed = new InfoFeed(); // constructor called + feed = new InfoFeed(); // new instance created; constructor called } function callFeed() { -- cgit v1.2.3 From e8c0c436c9aad0f3902a4e0826bf72de49bde12b Mon Sep 17 00:00:00 2001 From: Nemil Dalal Date: Thu, 14 Jan 2016 10:17:51 -0500 Subject: Added observer pattern, per barkthin's feedback --- solidity.html.markdown | 45 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index 71a44b92..3a5e8ff5 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -506,7 +506,8 @@ function remove() { // Steps: 1. Commit to something, 2. Reveal commitment sha3("some_bid_amount", "some secret"); // commit -// call contract's reveal function showing bid plus secret that hashes to SHA3 +// call contract's reveal function in the future +// showing bid plus secret that hashes to SHA3 reveal(100, "mySecret"); // B. Storage optimization @@ -531,7 +532,45 @@ reveal(100, "mySecret"); // Contracts must be manually called to handle time-based scheduling; can create external // code to regularly ping, or provide incentives (ether) for others to -// E. State machines +// E. Observer Pattern +// An Observer Pattern lets you register as a subscriber and +// register a function which is called by the oracle (note, the oracle pays +// for this action to be run) +// Some similarities to subscription in Pub/sub + +// This is an abstract contract, both client and server classes import +// the client should implement +contract SomeOracleCallback { + function oracleCallback(int _value, uint _time, bytes32 info) external; +} + +contract SomeOracle { + SomeOracleCallback[] callbacks; // array of all subscribers + + // Register subscriber + function addSubscriber(SomeOracleCallback a) { + callbacks.push(a); + } + + function notify(value, time, info) private { + for(uint i = 0;i < callbacks.length; i++) { + // all called subscribers must implement the oracleCallback + callbacks[i].oracleCallback(value, time, info); + } + } + + function doSomething() public { + // Code to do something + + // Notify all subscribers + notify(_value, _time, _info); + } +} + +// Now, your client contract can addSubscriber by importing SampleOracleCallback +// and registering with Sample Oracle + +// F. State machines // see example below for State enum and inState modifier @@ -748,7 +787,7 @@ someContractAddress.callcode('function_name'); - Libraries ## Style -- Python's [PEP8](https://www.python.org/dev/peps/pep-0008/) is used as the baseline style guide, including its general philosophy) +- Python's [PEP8](https://www.python.org/dev/peps/pep-0008/) is used as the baseline style guide, including its general philosophy ## Future To Dos - New keywords: protected, inheritable -- cgit v1.2.3 From 810108ee73a6acc882155ec7ff1bc07983ced05e Mon Sep 17 00:00:00 2001 From: Nemil Dalal Date: Thu, 14 Jan 2016 14:01:45 -0500 Subject: Fixed error in name --- solidity.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index 3a5e8ff5..a511bbb3 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -567,8 +567,8 @@ contract SomeOracle { } } -// Now, your client contract can addSubscriber by importing SampleOracleCallback -// and registering with Sample Oracle +// Now, your client contract can addSubscriber by importing SomeOracleCallback +// and registering with Some Oracle // F. State machines // see example below for State enum and inState modifier -- cgit v1.2.3 From eaf0307775733fddebe308a5a98b7b386f3820cf Mon Sep 17 00:00:00 2001 From: Nemil Dalal Date: Mon, 20 Jun 2016 14:56:44 -0400 Subject: Security additions + edits (#2281) * Edits with a focus on security risks * Modified example * Flip sign - example of the risk of Solidity code when published to an append only ledger * Fixed formatting --- solidity.html.markdown | 133 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 97 insertions(+), 36 deletions(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index a511bbb3..9bf5bf4d 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -8,7 +8,7 @@ contributors: Solidity lets you program on [Ethereum](https://www.ethereum.org/), a blockchain-based virtual machine that allows the creation and -execution of smart contracts, without needing centralized or trusted parties. +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 @@ -18,8 +18,17 @@ global variables. Some Ethereum contract examples include crowdfunding, voting, 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 explicitly marked, and subject to change. Pull requests welcome. +features are typically marked, and subject to change. Pull requests welcome. ```javascript // First, a simple Bank contract @@ -40,6 +49,7 @@ contract SimpleBank { // CamelCase // Declare state variables outside function, persist through life of contract // dictionary that maps addresses to balances + // always be careful about overflow attacks with numbers mapping (address => uint) private balances; // "private" means that other contracts can't directly query balances @@ -49,7 +59,7 @@ contract SimpleBank { // CamelCase // 'public' makes externally readable (not writeable) by users or contracts // Events - publicize actions to external listeners - event DepositMade(address accountAddress, uint amount); + event LogDepositMade(address accountAddress, uint amount); // Constructor, can receive one or many variables here; only one allowed function AcmeBank() { @@ -65,7 +75,7 @@ contract SimpleBank { // CamelCase // no "this." or "self." required with state variable // all values set to data type's initial value by default - DepositMade(msg.sender, msg.value); // fire event + LogDepositMade(msg.sender, msg.value); // fire event return balances[msg.sender]; } @@ -76,11 +86,14 @@ contract SimpleBank { // CamelCase /// @return The balance remaining for the user function withdraw(uint withdrawAmount) public returns (uint remainingBal) { if(balances[msg.sender] >= withdrawAmount) { + // Note the way we deduct the balance right away, before sending - due to + // the risk of a recursive call that allows the caller to request an amount greater + // than their balance balances[msg.sender] -= withdrawAmount; if (!msg.sender.send(withdrawAmount)) { - // to be safe, may be sending to contract that - // has overridden 'send' which may then fail + // increment back only on fail, as may be sending to contract that + // has overridden 'send' on the receipt end balances[msg.sender] += withdrawAmount; } } @@ -150,8 +163,10 @@ address public owner; // All addresses can be sent ether owner.send(SOME_BALANCE); // returns false on failure -if (owner.send) {} // typically wrap in 'if', as contract addresses have -// functions have executed on send and can fail +if (owner.send) {} // REMEMBER: wrap in 'if', as contract addresses have +// functions executed on send and these can fail +// Also, make sure to deduct balances BEFORE attempting a send, as there is a risk of a recursive +// call that can drain the contract // can override send by defining your own @@ -351,8 +366,11 @@ function b() { // access events from outside blockchain (with lightweight clients) // typically declare after contract parameters +// Typically, capitalized - and add Log in front to be explicit and prevent confusion +// with a function call + // Declare -event Sent(address from, address to, uint amount); // note capital first letter +event LogSent(address indexed from, address indexed to, uint amount); // note capital first letter // Call Sent(from, to, amount); @@ -396,7 +414,10 @@ onlyIfState(State.A) modifier checkValue(uint amount) { _ if (msg.value > amount) { - msg.sender.send(amount - msg.value); + uint amountToRefund = amount - msg.value; + if (!msg.sender.send(amountToRefund)) { + throw; + } } } @@ -409,6 +430,21 @@ modifier checkValue(uint amount) { // Syntax same as javascript, but no type conversion from non-boolean // to boolean (comparison operators must be used to get the boolean val) +// For loops that are determined by user behavior, be careful - as contracts have a maximal +// amount of gas for a block of code - and will fail if that is exceeded +// For example: +for(uint x = 0; x < refundAddressList.length; x++) { + if (!refundAddressList[x].send(SOME_AMOUNT)) { + throw; + } +} + +// Two errors above: +// 1. A failure on send stops the loop from completing, tying up money +// 2. This loop could be arbitrarily long (based on the amount of users who need refunds), and +// therefore may always fail as it exceeds the max gas for a block +// Instead, you should let people withdraw individually from their subaccount, and mark withdrawn + // 7. OBJECTS/CONTRACTS @@ -587,13 +623,13 @@ contract CrowdFunder { address public fundRecipient; // creator may be different than recipient uint public minimumToRaise; // required to tip, else everyone gets refund string campaignUrl; + byte constant version = 1; // Data structures enum State { Fundraising, - ExpiredRefundPending, - Successful, - ExpiredRefundComplete + ExpiredRefund, + Successful } struct Contribution { uint amount; @@ -604,11 +640,11 @@ contract CrowdFunder { State public state = State.Fundraising; // initialize on create uint public totalRaised; uint public raiseBy; + uint public completeAt; Contribution[] contributions; - event fundingReceived(address addr, uint amount, uint currentTotal); - event allRefundsSent(); - event winnerPaid(address winnerAddress); + event LogFundingReceived(address addr, uint amount, uint currentTotal); + event LogWinnerPaid(address winnerAddress); modifier inState(State _state) { if (state != _state) throw; @@ -620,10 +656,13 @@ contract CrowdFunder { _ } + // Wait 6 months after final contract state before allowing contract destruction modifier atEndOfLifecycle() { - if(state != State.ExpiredRefundComplete && state != State.Successful) { + if(!((state == State.ExpiredRefund || state == State.Successful) && + completeAt + 6 months < now)) { throw; } + _ } function CrowdFunder( @@ -651,9 +690,10 @@ contract CrowdFunder { ); totalRaised += msg.value; - fundingReceived(msg.sender, msg.value, totalRaised); + LogFundingReceived(msg.sender, msg.value, totalRaised); checkIfFundingCompleteOrExpired(); + return contributions.length - 1; // return id } function checkIfFundingCompleteOrExpired() { @@ -663,9 +703,9 @@ contract CrowdFunder { // could incentivize sender who initiated state change here } else if ( now > raiseBy ) { - state = State.ExpiredRefundPending; - refundAll(); + state = State.ExpiredRefund; // backers can now collect refunds by calling getRefund(id) } + completeAt = now; } function payOut() @@ -676,22 +716,27 @@ contract CrowdFunder { throw; } - winnerPaid(fundRecipient); + + LogWinnerPaid(fundRecipient); } - function refundAll() + function getRefund(id) public - inState(State.ExpiredRefundPending) + inState(State.ExpiredRefund) { - uint length = contributions.length; - for (uint i = 0; i < length; i++) { - if(!contributions[i].contributor.send(contributions[i].amount)) { - throw; - } + if (contributions.length <= id || id < 0 || contributions[id].amount == 0 ) { + throw; + } + + uint amountToRefund = contributions[id].amount; + contributions[id].amount = 0; + + if(!contributions[id].contributor.send(amountToSend)) { + contributions[id].amount = amountToSend; + return false; } - allRefundsSent(); - state = State.ExpiredRefundComplete; + return true; } function removeContract() @@ -700,13 +745,13 @@ contract CrowdFunder { atEndOfLifecycle() { selfdestruct(msg.sender); + // creator gets all money that hasn't be claimed } function () { throw; } } // ** END EXAMPLE ** - // 10. OTHER NATIVE FUNCTIONS // Currency units @@ -732,8 +777,14 @@ sha3("ab", "cd"); ripemd160("abc"); sha256("def"); +// 11. SECURITY + +// Bugs can be disastrous in Ethereum contracts - and even popular patterns in Solidity, +// may be found to be antipatterns -// 11. LOW LEVEL FUNCTIONS +// See security links at the end of this doc + +// 12. LOW LEVEL FUNCTIONS // call - low level, not often used, does not provide type safety successBoolean = someContractAddress.call('function_name', 'arg1', 'arg2'); @@ -742,7 +793,7 @@ successBoolean = someContractAddress.call('function_name', 'arg1', 'arg2'); someContractAddress.callcode('function_name'); -// 12. STYLE NOTES +// 13. STYLE NOTES // Based on Python's PEP8 style guide // Quick summary: @@ -753,7 +804,7 @@ someContractAddress.callcode('function_name'); // else should be placed on own line -// 13. NATSPEC COMENTS +// 14. NATSPEC COMENTS // used for documentation, commenting, and external UIs // Contract natspec - always above contract definition @@ -773,9 +824,8 @@ someContractAddress.callcode('function_name'); - [Solidity Docs](https://solidity.readthedocs.org/en/latest/) - [Solidity Style Guide](https://ethereum.github.io/solidity//docs/style-guide/): Ethereum's style guide is heavily derived from Python's [pep8](https://www.python.org/dev/peps/pep-0008/) style guide. - [Browser-based Solidity Editor](http://chriseth.github.io/browser-solidity/) -- [Gitter Chat room](https://gitter.im/ethereum/solidity) +- [Gitter Solidity Chat room](https://gitter.im/ethereum/solidity) - [Modular design strategies for Ethereum Contracts](https://docs.erisindustries.com/tutorials/solidity/) -- Editor Snippets ([Ultisnips format](https://gist.github.com/nemild/98343ce6b16b747788bc)) ## Sample contracts - [Dapp Bin](https://github.com/ethereum/dapp-bin) @@ -783,13 +833,24 @@ someContractAddress.callcode('function_name'); - [ConsenSys Contracts](https://github.com/ConsenSys/dapp-store-contracts) - [State of Dapps](http://dapps.ethercasts.com/) +## Security +- [Thinking About Smart Contract Security](https://blog.ethereum.org/2016/06/19/thinking-smart-contract-security/) +- [Smart Contract Security](https://blog.ethereum.org/2016/06/10/smart-contract-security/) +- [Hacking Distributed Blog](http://hackingdistributed.com/) + ## Information purposefully excluded - Libraries ## Style - Python's [PEP8](https://www.python.org/dev/peps/pep-0008/) is used as the baseline style guide, including its general philosophy +## Editors +- [Vim Solidity](https://github.com/tomlion/vim-solidity) +- Editor Snippets ([Ultisnips format](https://gist.github.com/nemild/98343ce6b16b747788bc)) + ## Future To Dos - New keywords: protected, inheritable +- 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 -- cgit v1.2.3 From acd1ac461145fa48fde52d8cadfd5d01fdba512a Mon Sep 17 00:00:00 2001 From: pnf408 Date: Tue, 27 Sep 2016 07:41:22 -0700 Subject: corrections in mapping example (#2371) fixed two small errors in the example mapping called balances --- solidity.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index 9bf5bf4d..0ad8af32 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -230,9 +230,9 @@ mapping (string => uint) public balances; balances["charles"] = 1; console.log(balances["ada"]); // is 0, all non-set key values return zeroes // 'public' allows following from another contract -contractName.balances("claude"); // returns 1 +contractName.balances("charles"); // returns 1 // 'public' created a getter (but not setter) like the following: -function balances(address _account) returns (uint balance) { +function balances(string _account) returns (uint balance) { return balances[_account]; } -- cgit v1.2.3 From 9453efb8453d57b719c68620c5f7ce36751cfc90 Mon Sep 17 00:00:00 2001 From: Miguel Mota Date: Fri, 23 Dec 2016 10:47:03 -0800 Subject: solidity contract name convention CamelCase to CapWords (#2606) --- solidity.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index 0ad8af32..5b0ac3a3 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -45,7 +45,7 @@ features are typically marked, and subject to change. Pull requests welcome. /* 'contract' has similarities to 'class' in other languages (class variables, inheritance, etc.) */ -contract SimpleBank { // CamelCase +contract SimpleBank { // CapWords // Declare state variables outside function, persist through life of contract // dictionary that maps addresses to balances -- cgit v1.2.3 From 9e8a3d73b687b3b4ee3558ceef2c1944f7d4051c Mon Sep 17 00:00:00 2001 From: Nemil Dalal Date: Wed, 15 Mar 2017 02:16:33 -0700 Subject: Fixed misnamed contract initializer (#2650) References: https://github.com/adambard/learnxinyminutes-docs/issues/2642 --- solidity.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index 5b0ac3a3..602d74f0 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -62,7 +62,7 @@ contract SimpleBank { // CapWords event LogDepositMade(address accountAddress, uint amount); // Constructor, can receive one or many variables here; only one allowed - function AcmeBank() { + function SimpleBank() { // msg provides details about the message that's sent to the contract // msg.sender is contract caller (address of contract creator) owner = msg.sender; -- cgit v1.2.3 From b15f719178803a3952e0b8f56b4e24752f22e2b5 Mon Sep 17 00:00:00 2001 From: sc0Vu Date: Tue, 25 Jul 2017 18:32:29 +0800 Subject: [solidity/en] Add version pragma --- solidity.html.markdown | 3 +++ 1 file changed, 3 insertions(+) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index 602d74f0..d9b33ed4 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -37,6 +37,9 @@ features are typically marked, and subject to change. Pull requests welcome. // simple_bank.sol (note .sol extension) /* **** START EXAMPLE **** */ +// Declare the source file compiler version. +pragma solidity ^0.4.2; + // Start with Natspec comment (the three slashes) // used for documentation - and as descriptive data for UI elements/actions -- cgit v1.2.3 From 985d23a52b76593a120adff5381c2df3a80fe298 Mon Sep 17 00:00:00 2001 From: HairyFotr Date: Wed, 23 Aug 2017 10:14:39 +0200 Subject: Fix a bunch of typos --- solidity.html.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index 602d74f0..a501befd 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -188,7 +188,7 @@ string n = "hello"; // stored in UTF8, note double quotes, not single // string utility functions to be added in future // prefer bytes32/bytes, as UTF8 uses more storage -// Type inferrence +// Type inference // var does inferred typing based on first assignment, // can't be used in functions parameters var a = true; @@ -484,7 +484,7 @@ contract MyContract is abc, def("a custom argument to def") { function z() { if (msg.sender == owner) { def.z(); // call overridden function from def - super.z(); // call immediate parent overriden function + super.z(); // call immediate parent overridden function } } } @@ -804,7 +804,7 @@ someContractAddress.callcode('function_name'); // else should be placed on own line -// 14. NATSPEC COMENTS +// 14. NATSPEC COMMENTS // used for documentation, commenting, and external UIs // Contract natspec - always above contract definition -- cgit v1.2.3 From e27533f7d108c351f3024541e611457509d3d833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=20Polykanine=20A=2EK=2EA=2E=20Menelion=20Elens=C3=BA?= =?UTF-8?q?l=C3=AB?= Date: Tue, 26 Sep 2017 23:16:13 +0300 Subject: [solidity/en] Fixed #2873 --- solidity.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'solidity.html.markdown') diff --git a/solidity.html.markdown b/solidity.html.markdown index fc54d6e4..c1f910fd 100644 --- a/solidity.html.markdown +++ b/solidity.html.markdown @@ -262,7 +262,7 @@ Bank b = Bank({ // or Bank c = Bank(msg.sender, 5); -c.amount = 5; // set to new value +c.balance = 5; // set to new value delete b; // sets to initial value, set all variables in struct to 0, except mappings -- cgit v1.2.3