###### 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>