This document provides an overview of Solidity programming concepts for developing smart contracts on Ethereum, including how to compile contracts, basic language features like comments and data types, documentation features like NatSpec, structs, conditional expressions, variables, mappings, inheritance, and function modifiers. It also discusses gas costs and calling methods between contracts.
Ethereum Developers
Community
Learning Solidity
ArnoldPham
Lunyr Inc.
https://www.linkedin.com/in/arnoldpham/
Unless otherwise stated, these slides are licensed under the Creative Commons Attribution-
NonCommercial 3.0 License (https://creativecommons.org/licenses/by-nc/3.0/us/)
Version Pragma
• Annotatessource files with a prerequisite
• Comes from semantic versioning which is widely used in the JavaScript
community (https://docs.npmjs.com/misc/semver)
^pragma solidity ^0.4.0 means >= compiler version 0.4.0 but <0.5.0
6.
Comments
Use // or/*...*/
pragma solidity ^0.4.0;
/*
Multisignature Wallet for requiring multiple owners to approve a transaction
*/
contract MultiSigWallet{
address[] public owners;
uint public required; // the number of owner approval required
}
7.
Natspec documentation
Produced asan object when you call a contract object from eth.compile.solidity(source)
Contract objects have the following properties
• code
• info
• source
• language
• languageVersion
• compilerVersion
• abiDefinition
• userDoc
• the Natspec Doc for users
• developerDoc
• the Natspec Doc for developers
8.
Natspec
@title: This isa title that should describe the contract and go above the contract
definition
@author: The name of the author of the contract. Should also go above the
contract definition.
@notice: Represents user documentation. This is the text that will appear to the
user to notify him of what the function he is about to execute is doing
@dev: Represents developer documentation. This is documentation that would
only be visible to the developer.
@param: Documents a parameter just like in doxygen. Has to be followed by the
parameter name.
@return: Documents the return type of a contract's function.
9.
Structs
• Advantageous fordescribing a set of variables that will be repeatedly used to
describe something
• Defines a new type
• Cheaper to use than abstract contracts which require paying gas for contract
creation
10.
Structs example
Imagine youhave a contract that registers people, and will do that repeatedly
struct Person{
string name;
uint birthdate;
enum gender;
}
mapping (uint => Person) people;
uint personID;
11.
Conditional Expressions
Uses controlstructures that are typical in other languages
1. if
2. else
3. while
4. do
5. for
6. break
7. continue
8. return
9. ? :
12.
Warning with loops
Operationscost gas so it is best to construct loops to repeat a known number of
times if possible
13.
Boolean Expressions
Widely usedfor throw, which reverses all side effects
function transfer(address _to, uint256 _value) returns (bool) {
var senderBalance = balances[msg.sender];
if (senderBalance >= _value && _value > 0) {
senderBalance -= _value;
balances[msg.sender] = senderBalance;
balances[_to] += _value;
Transfer(msg.sender, _to, _value);
return true;
}
return false;
}
14.
Variables
State and localvariables are in storage by default
contract Products {
mapping (address->uint) owned
}
15.
Mappings
Only allowed forstate variables
Mappings can be seen as hashtables which are virtually initialized such that
every possible key exists and is mapped to a value
16.
Global variables
1. msg.sender
a.the address of the sender in the current call
2. msg.value
a. the amount of wei sent with the message
3. now
a. the current unix timestamp in seconds
17.
Visibility for functionsand state variables
• Public
• can be called either internally or from messages
• default for functions
• Private
• can only be called from the contract that it is defined in and not from
derived contracts
• Internal
• can be called from the contract it is defined in or in derived contracts
• default for state variables
• External
• can only be called from other contracts and via transactions
• cannot be called internally
18.
Inheritance
• For contractsinheriting from multiple other contracts, only a single contract is
created on the blockchain
• The code from the base contracts is copied into the final contract
“super”
• Use “super”to call the next position in line in the inheritance hierarchy
• If Base1 calls a function of super, then it will call it on Base2 rather than on
Base1
Bytes32
• Each bytes32can store up to 32 letters (ASCII): each character is a byte.
• The EVM has a word-size of 32 bytes, so it is "optimized" for dealing with data
in chunks of 32 bytes. (Compilers, such as Solidity, have to do more work and
generate more bytecode when data isn't in chunks of 32 bytes, which
effectively leads to higher gas cost.)
24.
Gas costs
• ~20,000gas when a value is set to non-zero from zero
• ~5,000 gas when writing to existing storage or setting a value to zero
• ~15,000 gas refund when a non-zero value is set to zero.
#3 Solidity is a statically typed language. The type of every variable must be specified at compile-time
#6 Allows changes that do not modify the left-most non-zero digit
#10 http://ethereum.stackexchange.com/questions/8615/child-contract-vs-struct
Under most circumstances, data structures, even complicated ones, should be structs.
Here are some reasons to choose structs:
Contracts are more expensive. You'll have to pay for the contract's creation initially, and every time you access it, you'll need to pay for a call to another contracts. This is much, much more expensive than a sha3 for a lookup inside the contract's own storage.
Contracts must replicate code. Every contract must contain the logic for setting and altering values, which you must pay for in gas. A struct needs only set of functions.
Contracts are exposed. Anyone can send a message to a contract. If you use a contract for storing data structures, you'll have to manage access manually.
Libraries might be what you're actually looking for. If you find yourself looking for functions on a data structure (i.e. foo.bar()), you can use a library contract to do it without the additional complexity of creating contracts for every instance.
Here are some reasons where contracts would be superior:
Contracts can be polymorphic. A contract could potentially contain arbitrary code. This allows multiple types to be intermingled, or even to have users bring their own logic.
The logic will be split. In this registrar contract each Deed could have been a struct. By making Deeds their own contracts, there is less of an attack surface for the Deeds themselves, reducing the chance of another TheDAO-scale disaster.
Contracts are exposed. If users have to configure their data structures, having a unique address they can interface with directly may prove simpler.
Contracts are contracts. A child contract can do anything a contract can do. If the data structures, for some reason, would own things as an address would, then having a contract would be far superior. A contract can directly hold Ether, as opposed to a struct sharing the main contract's balance with other structs.
However, these are less common. My advice: try it with structs first, and use data structure contracts as a last resort.
#15 Solidity is a statically typed language. The type of every variable must be specified at compile-time