# Quorum 研究筆記(11/14) ## solidity入門 ### ERC20(26) 官網定義:design and issue your own cryptocurrency 如果今天要創立一個幣,那我還要自己創一個區塊鏈,那就創一個以太坊,讓每個人都可以創自己的幣以及智能合約,可是每個人的幣如果標準都不同會無法相容,所以就制定ERC20標準,只要有用到以下方法,即稱符合ERC20: ![](https://i.imgur.com/cbZRgq5.jpg) 只要方法裡面有revert,當次交易會被拒絕掉 #### transfer原理 小名要轉給小黃5個代幣,並不是直接把幣轉給小黃,而是轉幣給智能合約,直接修改鏈上mapping的資料(要付gas),幣都不是存在自己這邊,而是存在智能合約之中。 ``` function approve(address spender, uint tokens) public returns (bool success){ allowed[msg.sender][spender] = tokens; emit approval(msg.sender, spender, tokens); return true; } function transferfrom(address from, address to, uint tokens) public returns(bool success){ balances[from] = balances[from] - sub(tokens); allowed[from][msg.sender] = allowed[from][msg.sender].sub(tokens); balances[to] = balances[to].add(tokens); emit transfer(from, to, tokens); return true; } ``` 使用者同意DEX(Decentralized Exchange去中心化交易所)使用自己的5個代幣,dex就會轉移那5個代幣給自己。但系統不會檢查使用者是否真的有五個代幣,所以使用者可以預先批准dex使用自己還沒有的代幣。 ### 異常exception(27) 如何限制可以呼叫我制定的方法的人? ``` address public owner = 0x..... function fu_abc() public{ if(msg.sender == owner) abc++; } ``` 透過if的方法,我們就可以限制必須要是owner才可以存取該方法 ``` function fu_abc() public{ require(owner == msg.sender, "使用者不對");//true or false require(msg.value >= 10000); abc++; } ``` 如果require裡面的條件為false,則這個方法會跳出,整個交易會直接壞掉;且會印出後面的字串。 另外,還有以下的保護方式: ``` function ex1(uint x) public{ if(x < 100){ revert("x can't be smaller than 100!") } interger_1 = x; } function ex2(uint x) public{ interger_1 = x; assert(integer_1 >= 100);//if the statement is false, then it'll fail } ``` 不管是revert、assert、require執行跳出,則該次交易所有的數值變動都會視為無效。 ![](https://i.imgur.com/EFLhQ0P.jpg) 我們通常會把assert擺在最後面作為最後一層的檢查,如果發生錯誤了通常就會是最嚴重的問題才會發生。 ## solidity 進階 ### modifier(28) ``` //自己定義一個modifier modifier onlyowner{ require(msg.sender == owner); _;//底下function執行內容的簡寫 require(integer1 <= 100);//可以執行完內容之後再檢查一次 } function myfunc(uint x) public onlyowner{ x++; integer1 += x; } ``` ``` modifier onlyowner(uint y){ require(y > 30); _;// } function myfunc(uint x) public onlyowner(x){ integer1 += x; } ``` ### (29?) ### 合約結構、哈希(30) ``` pragma solidity ^0.4.24 //大於0.4.24版本編譯即可 pragma solidity 0.4.24 //只能用0.4.24版本編譯 ``` 一個合約的基本樣子: ``` prama solidity ^0.4.24; contract class30{ address public owner; uint public integer; //全域變數 constructor() public { owner = msg.sender; integer = 0; } modifier onlyowner { require(msg.sender != owner); _; } function add_check_sender(uint x)public onlyowner{ integer += x; } } ``` #### hash方法 - 改變一點輸入,輸出巨變 - 無法導回內容 - 不同輸入即不同結果 ``` function keccok_256_2(string str1, string str2) public view returns(bytes32){ return keccok256(abi.encodePacked(str1,str2,msg.value,now,...)) //裡面可以裝很多東西 } ``` ``` function pay() public payable{ } //改變了coinbase的高度的值 //所以必須要pay完,底下的亂數產生器才能再產生一個不同的亂數 //因為亂數產生需要用到coinbase //粗糙的亂數產生器 function rendom() public view returns(uint){ bytes32 result = keccok256(block.coinbase, blockhash(block.number-1))); return uint(result) % 1000 / 1; } ``` ### library (31) 將一些共同需求的程式碼整理成大家都可以用的函式庫,加速每個人的開發進程。 例:照相app裡面有修圖library、錄影拍照library與qrcode library之類的。 ``` pragma solidity ^0.4.24; library safemath{ function add(uint a, uint b){ ... } function sub(uint256 a, uint256 b){ ... } } pragma solidity ^0.4.24; import"./safemath.sol" contract class31{ using safemath for uint; function use_add(uint a, uint b) public pure returns(uint){ return a.add(b); } //the result equal a+b //a.add(b)的a會對應到library的add中uint的a } ``` 為甚麼我們需要再寫一個library來乘除數字? 因為我們可以在safemath裡面多一個溢位防護機制,可進而避免駭客攻擊、避免資安疑慮。 ### address方法、餘額與自毀(32) ``` function myfunc() public{ address myaddress = 0x...; //我們可以對這個myaddress做甚麼? //查詢餘額myaddress.balance //轉幣myaddress.transfer //轉幣myaddress.send function func1() public view returns(uint){ return owner.balance; }//傳回使用者餘額 function func2() public view returns(uint){ return address(this).balance; }//傳回這份智能合約的餘額 } ``` #### 這部影片後面斷掉 ### reference (33) - 變數存在記憶體(memory)還是鏈上(storage)?存在記憶體上代表只用一次,但如果存在鏈上,因為每個節點都幫你存資料,所以需耗費的gas較貴。 - 預設全域型變數就是storage,區域型為memory 全域型變數都是存在鏈上: ``` prama solidity ^0.4.24; contract class33{ uint public abc = 0; mapping(address->uint) public balance; function use() public pure returns(uint){ return 5; } } ``` 區域型變數代表存在memory,只有當次有效: ``` prama solidity ^0.4.24; contract class33{ uint public abc = 0; function use() public pure returns(uint){ uint ggg = 5; return ggg; } } ``` storage與memory為保留字: ``` struct fruit{ uint id; string name; } fruit[12] public fruitarray; mapping(address => fruit) public fruitmapping; function ex1(uint i, string n)public{ fruit storage fruit1 = fruitarray[0]; fruit1.id = i; fruit1.name = n; fruit storage fruit2 = fruitmapping[0x...]; fruit2.name = n; } function ex2(uint i, string n)public view{ //不會改變鏈上資訊 fruit memory fruit1 = fruitarray[0]; fruit1.id = i; fruit1.name = n; } ```