---
# System prepended metadata

title: KrypoCamp 第三週課前預習 Solidity

---

# KrypoCamp 第三週課前預習 Solidity

### Function Modifiers（函數修飾符）
透過宣告修飾符並掛載給已存在方法來調整方法行為

- 如函數一樣可傳入參數
- 宣告不可使用相同命名（不論參數類型）
- "_" 的意思是原方法的內容

```solidity=
modifier onlyOwner() { // Modifier
    _;
}

modifier checkOwner(address _addr) {
	require(_addr == owner, "Address is not the owner.");
		_;
}

```

```solidity=
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;

contract MyToken {
    address public owner;

    modifier onlyOwner() {
        require( msg.sender == owner, "Only owner can call this." );
        _;
    }
    
    modifier checkOwner(address _addr) {
        require(_addr == owner, "Address is not the owner.");
            _;
    }    

    function burn() public view onlyOwner {
        // ...
    }
    
    function mint() public view checkOwner( msg.sender ) {
        // ...
    }
}
```

### Events
智能合約中唯一能夠留下 Log 行為紀錄的方法
- 可用於追蹤。
- 可串接Log，用於訂閱事件

```solidity=
event HighestBidIncreased(address bidder, uint amount);
```

```solidity=
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.21 <0.9.0;

contract SimpleAuction {
    event HighestBidIncreased(address bidder, uint amount); // Event

    function bid() public payable {
        // ...
        emit HighestBidIncreased(msg.sender, msg.value); // Triggering event
    }
}
```

### Errors

遇到錯誤，回滾狀態（回到原本狀態），並且扣除/(不)返還手續費

- throw（不返還手續費）(現在不使用)
- assert（不返還手續費）
- require（返還未使用手續費 - 有條件檢查）
- revert（返回未使用手續費 - 無條件檢查）

```solidity=
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

/// Not enough funds for transfer. Requested `requested`,
/// but only `available` available.
error NotEnoughFunds();

contract Token {
    mapping(address => uint) balances;
    function transferThrowError() public {
        // revert();
        throw;
    }
    function transferAssertError() public {
        assert(false);
    }
    function transferRevertError() public {
        revert NotEnoughFunds();
    }
    function requireRevertError() public {
        require(false, "revert error");
    }
}
```

### Function Virtual, Override
```solidity=
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
}

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

contract MyToken is IERC20, IERC20Metadata {
    mapping(address => mapping(address => uint256)) private _allowances;

    constructor() {}

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        address owner = msg.sender;
        return true;
    }

    function name() public view virtual override returns (string memory) {
        return "We Are Gonna Make it.";
    }

    function symbol() public view virtual override returns (string memory) {
        return "WAGMI";
    }

    function decimals() public view virtual override returns (uint8) {
        return 18;
    }
}
```

### Address Method

`All three functions call, delegatecall and staticcall are very low-level functions and should only be used as a last resort as they break the type-safety of Solidity.`

以下幾個 address 方法都是屬於低階方法，不為可靠與預期，需要謹慎使用

- call
    - 呼叫指定合約函數，呼叫者為合約，環境為呼叫合約
- callcode
    - 呼叫指定合約函數，呼叫者為合約，環境為原合約
- delegatecall
    - 呼叫指定合約函數，呼叫者為原合約呼叫者，環境為原合約
- staticcall
    - 呼叫指定合約函數，只可讀

```solidity=
address(nameReg).call{value: 1 ether}(abi.encodeWithSignature("register(string)", "MyName"));
```

### ABI

- abi.encodeWithSelector(bytes4(keccak256(signature))
- abi.encodeWithSignature
- abi.encode
- abi.encodePacked

### Defi 智能合約導讀

#### Defi

> 去中心化金融是一種建立於區塊鏈上的金融，它不依賴券商、交易所或銀行等金融機構提供金融工具，而是利用區塊鏈上的智慧型合約進行金融活動。DeFi平台允許人們向他人借出或借入資金，交易加密貨幣，並在類似儲蓄的帳戶中獲得利息。

#### 什麼是自動化做市商（AMM）？

> 自動化做市商（AMM）是一種去中心化交易所（DEX）協議，以數學公式來為資產進行定價。資產不再像傳統交易所般使用訂單簿，而是由價格演算法來定價。

每種協議的公式皆不同。例如，Uniswap使用x * y = k ，其中x是流動池中一種代幣的數量，而y是另一種代幣的數量。在此公式中， k是一個固定常數，意味著流動池的總流動性永遠保持不變。其他AMM會按照其特定用例而使用不同的公式。但是，它們之間都有相似之處，就是通過演算法來確定價格。

#### 什麼是流動資金池？

> 流動性供應者（LP）將資金注入流動性資金池中。您可以把流動池想像為是一大筆可讓交易者進行交易的資金。流動性供應者會在其流動池的交易中賺取費用，作為向協議提供流動性的回報。在Uniswap的情況，流動性供應者存入兩個價值相等的代幣，例如是把50% ETH及50% DAI存到ETH/DAI池。

UniswapExchange v1

- [完整 Solidity](https://github.com/PhABC/uniswap-solidity/blob/master/contracts/uniswap/UniswapExchange.sol)
- [簡化 Solidity](https://gist.github.com/madeinfree/d1d0fd5c6bb3406174eb6394d407bb77)

UniswapExchange v2

- [官方 Solidity 版](https://github.com/Uniswap/v2-core)

#### 延伸讀物
[Solidity Tutorial](https://www.tutorialspoint.com/solidity/) 
[Solidity by Example](https://solidity-by-example.org/)
[深入智能合約 ABI](https://medium.com/taipei-ethereum-meetup/ethereum-%E6%99%BA%E8%83%BD%E5%90%88%E7%B4%84%E9%96%8B%E7%99%BC%E7%AD%86%E8%A8%98-%E6%B7%B1%E5%85%A5%E6%99%BA%E8%83%BD%E5%90%88%E7%B4%84-abi-268ececb70ae)