# 《Solidity 教程》合約結構

By [Samumu.eth](https://paragraph.com/@samumu) · 2022-03-01

---

在 Solidity 語言中，合約類似於其他面向物件程式設計語言中的類

每個合約中可以包含 狀態變數、 函數、 函數 、事件 Event、 結構體、 和 枚舉類型 的聲明，且合約可以從其他合約繼承。還有一些特殊的合約，例如如[庫](https://learnblockchain.cn/docs/solidity/contracts.html#libraries)和[介面](https://learnblockchain.cn/docs/solidity/contracts.html#interfaces).

本節用於幫助我們了解合約包含哪些內容，做一個簡單的入門，不會有細節的解釋與範例

[Section3. 類型](https://www.notion.so/Section3-d136705c8dc9457aa74f6bfb109e5f95) 和 [Section6. 合約](https://www.notion.so/Section6-94b3a5486c66451fae9ca3a6ef7af66b) 章節會比本節包含更多的說明

State Variables
---------------

狀態變數是永久地存儲在合約中的值

在 `Azuki.sol` 中使用：

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    contract Azuki is Ownable, ERC721A, ReentrancyGuard {
      uint256 public immutable maxPerAddressDuringMint;
      uint256 public immutable amountForDevs;
      uint256 public immutable amountForAuctionAndDev;
    
      mapping(address => uint256) public allowlist;
        //...
        uint256 public constant AUCTION_START_PRICE = 1 ether;
      uint256 public constant AUCTION_END_PRICE = 0.15 ether;
      uint256 public constant AUCTION_PRICE_CURVE_LENGTH = 340 minutes;
      uint256 public constant AUCTION_DROP_INTERVAL = 20 minutes;
      uint256 public constant AUCTION_DROP_PER_STEP =
        (AUCTION_START_PRICE - AUCTION_END_PRICE) /
          (AUCTION_PRICE_CURVE_LENGTH / AUCTION_DROP_INTERVAL);
        //...
        string private _baseTokenURI;
    }
    

這些變數宣告便是該合約中所有的狀態變數，下一章節會解釋各種狀態變數如何使用

Functions
---------

函數是代碼的可執行單元， 函數通常在合約內部定義，但也可以在合約外定義，在 `Azuki.sol` 中我們可以看到所有函數都被包在 `Contract Azuki` 裡面

在 `Azuki.sol` 中使用到的函數類型包含：

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    contract Azuki is Ownable, ERC721A, ReentrancyGuard {
        function publicSaleMint(uint256 quantity, uint256 callerPublicSaleKey) {
            //...
        }
        
        function auctionMint(uint256 quantity) external payable callerIsUser {
            //...
        }
        
        function isPublicSaleOn(
            uint256 publicPriceWei,
            uint256 publicSaleKey,
            uint256 publicSaleStartTime
          ) public view returns (bool) {
            //...
        }
        
        function getOwnershipData(uint256 tokenId)
            external
            view
            returns (TokenOwnership memory){
            //...
        }
        
        function endAuctionAndSetupNonAuctionSaleInfo(
            uint64 mintlistPriceWei,
            uint64 publicPriceWei,
            uint32 publicSaleStartTime
          ) external onlyOwner {
            //...
        }
        
        function _baseURI() internal view virtual override returns (string memory) {
            //...
        }
        
        function withdrawMoney() external onlyOwner nonReentrant {
            //...
        }
    }
    

只看函數宣告的話，我們並不能了解這個函數的確切用法，但卻可以了解這個函數：

*   能夠在哪使用 - 我們可以函數宣告中有些函數帶有 `external` , `public` , `internal` 這表示這個函數的可見性，其中 `private` 也是一種方式，不過這邊沒有使用到
    
*   需要提供什麼類型參數 - `()` 內所有的參數，可以看到其聲明方法與第一部分狀態變數雷同，以第一個函數 `publicSaleMint` 為例，他需要 caller 提供 `quantity` 和 `callerPublicSaleKey` 的值，且其類型必須是 `uint256`
    
*   會回傳什麼類型的資料 - `returns()` 內的參數，以 `isPublicSaleOn` 為例，這個函數會回傳 `bool` 也就是 True 或 False
    

Functions Modifiers
-------------------

函數修改器可以用來以聲明的方式修改函數語義， `Azuki.sol` 中使用：

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    contract Azuki is Ownable, ERC721A, ReentrancyGuard {
        //...
        modifier callerIsUser() {
        require(tx.origin == msg.sender, "The caller is another contract");
        _;
      }
        //...
    }
    

以上述函數部分 `auctionMint` 為例，後面 `callerIsUser` 就是修改器用法

**Events**
----------

事件是能方便地調用乙太坊虛擬機日誌功能的介面， `Azuki.sol` 中沒有使用到事件，不過這邊還是簡單說明一下用法

    pragma solidity >=0.4.21 <0.9.0;
    contract TinyAuction {
        event HighestBidIncreased(address bidder, uint amount); // 事件
    
        function bid() public payable {
            // ...
            emit HighestBidIncreased(msg.sender, msg.value); // 觸發事件
        }
    }
    

Struct Types
------------

結構體是可以將幾個變數分組的自定義類型， `Azuki.sol` 中使用：

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    contract Azuki is Ownable, ERC721A, ReentrancyGuard {
        //...
        struct SaleConfig {
        uint32 auctionSaleStartTime;
        uint32 publicSaleStartTime;
        uint64 mintlistPrice;
        uint64 publicPrice;
        uint32 publicSaleKey;
      }
        //...
    }
    

**Enum Types**
--------------

枚舉可用來創建由一定數量的「常量值」構成的自定義類型， `Azuki.sol` 中沒有使用到事件，不過這邊還是簡單說明一下用法

    pragma solidity >=0.4.0 <0.9.0;
    
    contract Upchain {
        enum State { Created, Locked, InValid } // 枚举
    }

---

*Originally published on [Samumu.eth](https://paragraph.com/@samumu/solidity-2)*
