---
# System prepended metadata

title: Solidity 相關筆記
tags: [Web3相關]

---

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