###### tags: `Web3相關` # Solidity 相關筆記 :::success :bookmark: 書籤 [TOC] ::: # 資料型態 ## 整數 每次宣告已8遞增做為區分,int8,int16...,int256。 <font size="5px">**int**</font> 為有符號整數型別(包括正負)。 ```javascript= int8 number = 127; // 只能表達-127~127的數字 (2^8) int256 number = 10000000; //共可表達 2^256/2 - 1 之值 (正負) int number = 1000000; // 直接這樣宣告等同於 int256 ``` <font size="5px">**uint**</font> - 無符號整數型別 - 通常用來表示**時間戳**或**貨幣**。 ```javascript= uint8 unumber = 255; // 只能表達0~255 (只有正數) uint256 unumber = 10000000; //共可表達 2^256 -1 uint unumber = 1000000; // 直接這樣宣告等同於 uint256 ``` ## 字串 ## 布林 ## 結構 通常會與陣列搭配使用。 <font size="5px">**Struct**</font> ```javascript= struct Item { string itemName; int256 itemPrice; uint256 createAt; string itemCount; uint256 imageHash; } Item[] public Items; function createItem(string _itemName,int256 _itemPrice,string _itemCount,uint256 _imageHash) public { Item memory newItem = Item({ itemName: _itemName, itemPrice: _itemPrice, itemCount: _itemCount, imageHash: _imageHash, createAt: now }); Items.push(newItem); } ``` ## 位址 用來表示錢包位址,**例如:0x8b6bB5e2E5DD42A3421C23A53966a80858aa7b54**。 通常也會和 **mapping** 搭配,利用該位址找到使用者的相關資料。 <font size="5px">**Address**</font> ```javascript= address addr = 0x8b6bB5e2E5DD42A3421C23A53966a80858aa7b54; addr.balance; // 查詢該帳號餘額 ``` ## Mapping 試想一種情況,一個使用者在平台許多購買商品,這時如果需要紀錄使用者購買過哪些商品時, 會需要紀錄該商品圖片的位址(Hash),這時可以利用mapping的方式去尋找使用者購買過哪些商品。 ```javascript= mapping(address => string[]) public UserInventory; // 新增商品時,將該商品照片的Hash新增到UserInventory陣列底下,之後要取出只需要將使用者的位址傳入即可。 function addItemToUserInventory(address _address , string _imagesHash){ ... UserInventory[_address].push(_imagesHash); // 將該圖片之Hash新增至UserInventory陣列 } function getUserInventoryData(address _address) public view returns (string[]) { return UserInventory[_address]; //當address傳入時,回傳該使用者位址對應到的陣列 } ``` # Event 透過Event(事件),可以去追蹤鏈上某些事件的發生以及該事件所包含的值。 透過Event來記錄事件值,能節省gas費用,並且於平台上可利用web3去監聽該事件是否發生。 參數被宣告為 **indexed** 時,可做為web3監聽事件的搜尋依據。 ```javascript= event Create(address indexed _from , address indexed _to,uint256 _time); function someFunction(address _from , address _to) public{ emit Create(_from, _to, block.timestamp); } ``` # 資料儲存 ## Storage (保存) 執行完後會將結果繼續留在合約變數內,如以下例子,執行完Numbers函式後,查看numbers陣列,陣列0的位置為0(原為1),陣列1的位置為2。 ```javascript= contract testStorage { int[] public numbers; function Numbers() public { numbers.push(1); numbers.push(2); //建立一個 new instance 參照為 numbers int[] storage myArray = numbers; // 將陣列0的位置修改為0 myArray[0] = 0; } } ``` ## Memory (暫存) 執行完畢後會將記憶體清空,用於Function內或條件判斷式的區域變數,如以下例子,執行完Numbers函式後,查看numbers陣列,陣列0的位置為1(第14行修改的無效只是暫時的), 陣列1的位置為2。 ```javascript= contract testMemory { int[] public numbers; function Numbers() public { numbers.push(1); numbers.push(2); //建立一個 new instance 參照為 numbers int[] memory myArray = numbers; // 將陣列0的位置修改為0 myArray[0] = 0; } } ``` # 錯誤處理 ## Require 用來針對外部傳入值驗證,可撰寫條件式判斷,當條件不符合時,會傳回剩餘尚未使用的**gas**, 並且回復所有狀態,通常用於前置條件檢查,require較節省gas。 ```javascript= contract testRequire{ address public owner; // 於建構時定義好owner constructor() public{ owner = msg.sender; } modifier onlyOwner(){ //檢查發送者是不是owner 不是的話就回傳Not Owner require(msg.sender == owner , "Not Owner!!!"); _; } } ``` ## Revert 與Require差不多,差別是Revert是用於條件式判斷內,也會傳回剩餘尚未使用的**gas**,並回復所有狀態。 ```javascript= contract testRevert{ address public owner; // 於建構時定義好owner constructor() public{ owner = msg.sender; } function deleteAllAccount(){ if(msg.sender != owner){ revert("You are not owner!!"); } ... } } ``` ## Assert # 系統預設變數 目前區塊的 **gas** 限制 ```javascript= block.gaslimit (uint) ``` 目前區塊的編號 ```javascript= block.number (uint) ``` 目前區塊的時間(非commit時間) ```javascript= block.timestamp (uint)// = now ``` 交易發起者的錢包位址 ```javascript= msg.sender (address) ``` 交易發起者的錢包餘額(單位為wei) ```javascript= msg.balance (uint) ``` 跟這筆交易一起被送出的eth數目(單位:wei) ```javascript= msg.value (uint) ``` 交易的發起者 ```javascript= tx.origin (address) ``` # 貨幣單位 - 1 ether = 1000 finney (10^3) - 1 ether = 1000000 szabo (10^6) - 1 ether = 1000000000000000000 wei (10^18) # ERC20 - 查詢發行token總量 `function totalSupply() constant returns (uint256 totalSupply)` - 查詢帳戶的token餘額 `function balanceOf(address _owner) constant returns (uint256 balance)` - 允許token轉移給某帳戶 參數1為可以領走自己代幣的對象的地址,參數2為token數量, `function approve(address _spender, uint256 _value) returns (bool success)` - A批准給B的代幣數量 `function allowance(address _owner, address _spender) constant returns (uint256 remaining)` ## 代幣發送與轉移 一開始先用帳戶1(所有代幣擁有者),執行**transfer**函式,發給帳戶2代幣, 之後**切換至帳戶2**,執行**approval**函式允許token轉移,帳戶位址為帳戶2位址,tokens可填多一點, **approval**成功後就可執行**transferFrom**函式,**from**為帳戶2位址,**to**為帳戶1位址, **tokens**上限就是當初執行**approve**填寫的數量。 # 參考資料 - <https://www.tutorialspoint.com/solidity/index.htm>