---
# System prepended metadata

title: 第一週作業

---

第一週作業
---
基礎：

1. 發行總量100億顆、位數18的代幣！

2. 發行總量10張的SBT。

3. 開發猜數字的合約（一個人設定，大家猜，有人猜中，就結束不讓其他人猜了）

進階： 

1. 發行有盲盒機制的NFT！

2. 理解ERC721A與ERC721的差異，並實作ERC721A合約，實際比較差異！
---
## 基礎​1

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract Basic0106_1 is ERC20 {

    constructor() ERC20("Basic One", "BO") {
        _mint(msg.sender, 10 ** 10);
    }

}
```

---
## ***# Refactor***
```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract Basic0106_1 is ERC20 {

    uint8 public decimal;
    uint256 public maxSupply;

    constructor(
        string memory _name, 
        string memory _symbol,
        uint8 _decimal,
        uint256 _maxSupply
        ) ERC20(_name, _symbol){
        decimal = _decimal;
        maxSupply = _maxSupply;
    }
    
    function decimals() public view override returns (uint8) {
        return decimal;
    }

    function mint (uint256 amount) external {
        require(amount + totalSupply() <= maxSupply, "over max supply.");
        _mint(msg.sender, amount);
    }
}

```

## 基礎​2

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract Advanced0106_2 is ERC721 {

    uint256 public availableQuantity = 10;

    constructor() ERC721("SBT Token", "SBT") {}

    function mint(address to, uint256 quantity) external payable {
        require(0 <= availableQuantity-quantity , "Not available quantity");
        availableQuantity = availableQuantity-quantity;
        _mint(to, quantity);//使用錯誤
    }

    function transferFrom(address from, address to, uint256 tokenId) public virtual override {
        require(
            from == address(0) || to == address(0),
            "You cannot transfer this token"
        );
    }

}

```

---
## ***# Refactor***
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract Advanced0106_2 is ERC721 {

    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;
    
    uint256 public maxSupply;

    modifier avaialbeMint(uint256 amount) {
        require(amount + _tokenIds.current() <= maxSupply, "over max supply.");
        _;
    }

    constructor(
        string memory _name, 
        string memory _symbol, 
        uint256 _maxSupply)
        ERC721(_name, _symbol){
        maxSupply = _maxSupply;
    }
    
    function mint (uint256 amount) external avaialbeMint(amount){
       for(uint256 i=0; i < amount ; i++){
            uint256 tokenId = _tokenIds.current();
            _mint(msg.sender, tokenId);
           _tokenIds.increment();
       }
    }
    
    function transferFrom(address from, address to, uint256 tokenId) public override {
        require(
            from == address(0) || to == address(0),
            "You cannot transfer this token"
        );
    }
}
```

## 基礎​3

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

contract Basic0106_3 {

    event GuessResult(string message);

    address public owner; 
    uint256 public targetNumber;
    bool public result;
    
    constructor() {
        owner = msg.sender; 
    }

    modifier onlyOwner {
        require(msg.sender == owner);
      _;
    }

   function setTargetNumber(uint256 _newTargetNumber) external onlyOwner{
      targetNumber = _newTargetNumber; 
      result = false;
   }

    function guess(uint256 guessNumber) external {
        require(result == false, "Not started yet!");
        if(targetNumber == guessNumber) {
            emit GuessResult("Bingo!");
            result = true;
        }
        else {
            emit GuessResult("Not correct number!");
        }
        
    }

}
```

---
## ***# Refactor***
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

contract Basic0106_3 {

    event GuessResult(string message);

    mapping (address => bool) public guessRecord;
    
    struct GameInfo{
        uint256 minValue;
        uint256 maxValue;
        uint256 target;
        address winner;
        bool result;
    }

    GameInfo gameInfo;
    
    constructor (
        uint256 _min,
        uint256 _max,
        uint256 _target
    ){
        gameInfo = GameInfo(
            {
                minValue: _min,
                maxValue: _max,
                target: _target,
                winner: msg.sender,
                result: false
            }
        );
    } 
    
    modifier onlyWinner {
        require(gameInfo.winner == msg.sender);
      _;
    }

    function setTargetNumber(uint256 _newTargetNumber) external onlyWinner {
        require(gameInfo.result == true, "The game is still going!");
        gameInfo.target = _newTargetNumber; 
        gameInfo.result = false;
    }
    
    function guess(uint256 guessNumber) external {
        require(gameInfo.result == false, "The game hasn't started yet!");
        require(gameInfo.winner != msg.sender, "You are the host!");
        require(!guessRecord[msg.sender], "Already guessed.");
        
        guessRecord[msg.sender] = true;
        
        if(gameInfo.target == guessNumber) {
            gameInfo.winner = msg.sender;
            gameInfo.result = true;
            emit GuessResult("Bingo!");
        }
        else {
            emit GuessResult("Not correct number!");
        }
        
    }
    
    function getWinner () external view returns (address){
        return gameInfo.winner;
    }

}
```

## 進階​1

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract Advanced0106_1 is ERC721 {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;
    address public owner; 
    string url = "";

    constructor() ERC721("BlindBox", "BOX") {
        owner = msg.sender; 
    }

    modifier onlyOwner {
        require(msg.sender == owner);
      _;
    }

    function _baseURI() internal view  override returns (string memory) {
        return url;
    }

    function setUrl(string calldata _url) public onlyOwner {
        url = _url;
    }

    function mint(address to) public {
        uint256 tokenId = _tokenIds.current();
        _mint(to, tokenId);
        _tokenIds.increment();
    }
}
```

---
## ***# Refactor***
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract Advanced0106_1 is ERC721 {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    using Strings for uint256;

    address owner;
    uint256 public maxSupply = 10;
    bool private isOpened = false;

    modifier onlyOwner{
        require(msg.sender == owner);
        _;
    }

    constructor (string memory _name, string memory _symbol) ERC721(_name, _symbol){
        owner = msg.sender;
    }

    function openBlindBox() external onlyOwner{
        isOpened = true;
    }

    function _baseURI() internal pure override returns (string memory) {
        return "ipfs://QmXxZBg4RnGxC2dDxfUSAmxgGooHsoncPQgCLiNw8kj3Ls/";
    }

    function tokenURI(uint256 tokenId) public view override returns (string memory) {
        if (!isOpened){
            return _baseURI();
        }
        return string(abi.encodePacked("ipfs://QmWQcaFFCm9ofyVN2ZwGbTGopLEbQ6QSc2Xn1C7ekKAYDF/", tokenId.toString(), ".json"));
    }

    function mint (uint256 amount) external{
        require(amount + _tokenIds.current() < maxSupply, "Over max supply.");
        for(uint256 i = 0; i < amount ; i++){
            uint256 tokenId = _tokenIds.current();
            _mint(msg.sender, tokenId);
            _tokenIds.increment();
        }
    }

}
```

## 進階​2

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import "erc721a/contracts/ERC721A.sol";

contract Advanced0106_2 is ERC721A {

    constructor() ERC721A("ERC721A Token", "721AT") {}

    function mint(address to, uint256 quantity) external payable {
        _mint(to, quantity);
    }

    function transferFromByERC721A(
        address from,
        address to,
        uint256 tokenId
    ) external payable {
        transferFrom(from, to, tokenId);
    }

}

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract Advanced0106_2_2 is ERC721 {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    constructor() ERC721("ERC721 Token", "721T") {}

    function mint(address to) public {
        uint256 tokenId = _tokenIds.current();
        _mint(to, tokenId);
        _tokenIds.increment();
    }

    function batchMint(address to, uint256 quantity) external payable {
        for (uint i = 0; i < quantity; i++) {
                mint(to);
        }
    }

    function transferFromByERC721(
        address from,
        address to,
        uint256 tokenId
    ) external payable {
        _transfer(from, to, tokenId);
    }



}
```

---
## ***# Refactor***
```solidity

```




