Solidity 101 -
寫你第一張智能合約
Ming-der Wang, twitter @mingderwang
ming@Log4Analytics.com
王銘德
今天上課的目的
- 讓你至少能看得懂 Solidity 程式碼
- 動手做: 至少能寫你第一章"智能合約" Hello World
- 能執行你的合約, 跟別人交換合約來執行
如果你做了你的客製化 "tokens" (代幣)
- 透過你的Ether Wallet, 跟別個同學互相交換 tokens
什麼東西可以寫成或利用 S.C.
- 需要 3rd Party Trusts (“第三方信託) 時
- 需要公開透明, 卻又不能篡改的東西 (比如說, 歷史?)
- 你跟政府有簽合約嗎? 你為何相信政府的鈔票? (美金呢?)
例如:
- 眾籌募資: Digix , WeiFund
- 選舉, 選主委, 選 whatever: Counterparty Foundation
- ...
- 想些超大的應用? 你生活周遭發生的事, 能用 S.C.來解決嗎?
Dev Env
-
Use TEST-NET to Mine and Test Your Smart Contracts
-
Use Official Ethereum Wallet (Mist) to Run Your TEST-NET as Your Dev Env
-
Use Gist to Save Your Code
-
Use Solidity Real Time Compiler If You Want
-
Use eth or geth CLI When You Are An Expert
-
then, Deploy Your Code On Ethereum Main Network!
Ethereum Wallet
Solidity Realtime Compiler
Solidiy Features
- An object-oriented language
- Types
- Structs
- Mappings (a kind of Arrays)
- Arrays
- address' Methods
- Data Location
- Functions and Exceptions
- Good documents!
Mortal
contract mortal {
address owner;
function mortal() {
owner = msg.sender; }
/* Function to recover the funds on the contract */
function kill() {
if (msg.sender == owner)
selfdestruct(owner); }
}
HelloWorld
contract helloworld is mortal {
/* helloworld inherits all behaviors of mortal, such as function mortal(), kill() and owner */
string storeData;
function set(string x) {
storeData = x; }
function get() constant returns (string data) {
return storeData; }
}
Object-Oriented - inheritance
Types
bool
int8, int16, int24 ... int256
uint8, uint16, ... uint256
uint and int are aliases for uint256 and int256,
address
string
bytes1, bytes2, bytes3, ..., bytes32.
byte is an alias for bytes1
structs
struct Funder { address addr; uint amount; }
- NO rational number so far.
Implicit Conversions
- Compiler will do that for you if possible.
- In general, an implicit conversion between value-types is possible if it makes sense semantically and no information is lost.
- Any type that can be converted to uint160 can also be converted to address.
Explicit Conv.
int8 y = -3; uint x = uint(y);
Type Deduction
uint20 x = 0x123; var y = x;
// y will be unit20 too
uint32 a = 0x12345678; uint16 b = uint16(a); // b will be 0x5678 now
- The type is only deduced from the first assignment, so the loop in the following snippet is infinite, as i will have the type uint8 and any value of this type is smaller than 2000. for (var i = 0; i < 2000; i++) { ... }
mappings
- Mapping types are declared as mapping (_KeyType => _ValueType), where _KeyType can be almost any type except for a mapping and _ValueType can actually be any type, including mappings.
- Mappings are only allowed for state variables (or as storage reference types in internal functions).
- no length
contract MyToken { /* This creates an array with all balances */
mapping (address => uint256) public balanceOf;
function MyToken() {
balanceOf[msg.sender] = 21000000; }
}
Arrays
contract C { function f(uint len) { uint[] memory a = new uint[](7); bytes memory b = new bytes(len);// memory // Here we have a.length == 7 and b.length == len a[6] = 8; } }
- An array of fixed size k and element type T is written as T[k], an array of dynamic size as T[].
bytes and string
Variables of type bytes and string are special arrays. A bytes is similar to byte[], but it is packed tightly in calldata. string is equal to bytes but does not allow length or index access (for now).
- So bytes should always be preferred over byte[] because it is cheaper.
- also, array has a member called, length and push.
- push is for appending elements.
Functions and Exceptions
contract Sharer { function sendHalf(address addr) returns (uint balance) { if (!addr.send(msg.value/2)) throw; // also reverts the transfer to Sharer return this.balance; } }
Hands-On
To create a new contract, such as "Greeter"
https://www.ethereum.org/token#the-code
Hands-On 2
To use "MyToken" contract to send tokens
address' Methods
address holds a 20 byte value (size of an Ethereum address). Address types also have members, like send()
address x = 0x123; address myAddress = this; if (x.balance < 10 && myAddress.balance >= 10) x.send(10);
All contracts inherit the members of address, so it is possible to query the balance of the current contract using this.balance.
if the address is a contract
address nameReg = 0x72ba7d8e73fe8eb666ea66babc8116a41bfb10e2; nameReg.call("register", "MyName"); nameReg.call(bytes4(sha3("fun(uint256)")), a);
- call returns a boolean indicating whether the invoked function terminated (true) or caused an EVM exception (false).
- delegatecall is to use library code which is stored in another contract.
- callcode was available that did not provide access to the original msg.sender and msg.value values.
Data Location
“calldata”, which is a non-modifyable non-persistent area where function arguments are stored. Function parameters (not return parameters) of external functions are forced to “calldata” and it behaves mostly like memory.
- memory (which is not persisting)
- storage (where the state variables are held).
- calldata
Every complex type, i.e. arrays and structs, has an additional annotation, the “data location”.
Data Location (continue)
- Depending on the context, there is always a default, but it can be overridden by appending either storage or memory to the type.
- The default for function parameters (including return parameters) is memory, the default for local variables is storage and the location is forced to storage for state variables (obviously).
Example
contract c {
uint[] x; // the data location of x is storage
// the data location of memoryArray is memory
function f(uint[] memoryArray) {
x = memoryArray; // works, copies the whole array to storage
var y = x; // works, assigns a pointer, data location of y is storage
y[7]; // fine, returns the 8th element
y.length = 2; // fine, modifies x through y
delete x; // fine, clears the array, also modifies y
y = memoryArray; // not working
delete y; // not working
g(x); // calls g, handing over a reference to x
h(x); // calls h and creates an independent, temporary copy in memory
}
function g(uint[] storage storageArray) internal {}
function h(uint[] memoryArray) {}
}
delete
contract DeleteExample {
uint data;
uint[] dataArray;
function f() {
uint x = data;
delete x; // sets x to 0, does not affect data
delete data; // sets data to 0, does not affect x which still holds a copy
}
uint[] y = dataArray;
delete dataArray; // this sets dataArray.length to zero, but as uint[] is a complex object, also
// y is affected which is an alias to the storage object
// On the other hand: "delete y" is not valid, as assignments to local variables
// referencing storage objects can only be made from existing storage objects.
}
}
Solidity Doc
如何讓別人執行你的Contract
[ { "constant": false, "inputs": [], "name": "kill", "outputs": [], "type": "function" }, { "constant": false, "inputs": [ { "name": "x", "type": "string" } ], "name": "set", "outputs": [], "type": "function" }, { "constant": true, "inputs": [], "name": "get", "outputs": [ { "name": "data", "type": "string", "value": "hello CCLiang" } ], "type": "function" } ]
跟你的 Contract Address
0x141fd413A40a4163A8ecF1A02f902A1abE8ff7c5
寄給他們 Contract JSON
按 Show Interface
點擊
Contract Address
Contract JSON Interface
想執行別人的 Contract
點擊
填如地址跟Contract JSON
Hello Contract
我有哪些 DApps 可以參考
http://dapps.ethercasts.com/
我還可以用其他語言寫 S.C. 嗎?
- Solidity - Javascript/C++ like
- Serpent - Python-like
- LLL - Lisp-like
-
EtherScript - Scratch-like
- 類似早期的 Lego MindStroms
Ethereum-based
Bitcoin-based
- counterparty
- ...
Q & A
如果您喜歡這場演講內容,
你可以用 Ether 幣贊助我們
飲料, 場地, 和研究經費
Taipei Ethereum Meetup
Further Reading: https://medium.com/@ConsenSys/a-101-noob-intro-to-programming-smart-contracts-on-ethereum-695d15c1dab4#.wxbzewj7w
Solidity Tutorial
By Ming-der Wang
Solidity Tutorial
- 3,928