第一週作業 [2024年1月]
基礎:
1. 發行總量100億顆、位數18的代幣!
2. 發行總量10張的SBT。
3. 開發猜數字的合約(一個人設定,大家猜,有人猜中,就結束不讓其他人猜了)
進階:
1. 發行有盲盒機制的NFT!
2. 理解ERC721A與ERC721的差異,並實作ERC721A合約,實際比較差異!
=================================================
1.發行總量100億顆、位數18的代幣
```
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MyCoin01 is ERC20 {
address public admin;
uint256 maxSup;
constructor(string memory _name , string memory _symbol , uint256 _maxSup) ERC20(_name, _symbol) {
admin = msg.sender;
maxSup = _maxSup;
}
function mint(uint256 _amount) public {
//如果今天是Line Pay改用虛擬貨幣,那充值TWD的時候應該就會從官方錢包去mint,所以下面也要有後台burn的功能 應該就可以這樣去設計?
require(msg.sender == admin , "u r not admin");
require(totalSupply()+_amount < maxSup , "mint > maxSup");
_mint(msg.sender, _amount);
}
function burn(address user, uint256 x) public {
_burn(user,x);
}
}
```
2.發行總量10張的SBT。
疑問點1:safe版沒改revert也轉移不了,但沒safe的transferFrom就很正常,由於safe會檢查接收方是不是合約、if是合約->有沒有操作NFT的功能。 會不會是remix是虛擬錢包的關系?
疑問點2:部署的合約不一定會公開合約代碼-->safetransferFrom無法判斷對方能不能操作NFT,這樣會不會造成實戰時使用safetransferFrom的場景限制?
疑問點3:我看大部份人的邏輯都是mint給msg.sender,如果有一個場景:有一個女團要發NFT,條件是本人有到現場+後援會成員+限領一個 -> 所以會是人工處理,這種情況mint的方式應該是在constructor裡加一個address Owner,然後require只能由Owner去mint給address?
還是全部mint給Owner然後require由Owner去transfer 已有的NFT給申請領取的人?
以上2種好像都是可行,但個人偏好後者
疑問點4:好像不一定要import Counters.sol,但網絡上有些做法是用這個,單純是比較方便而已嗎
```
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
contract MyNFT is ERC721 {
uint256 MaxSupply = 10;
uint256 counter = 0;
constructor(string memory _name ,string memory _symbol , uint256 _MaxSupply) ERC721(_name, _symbol) {
MaxSupply = _MaxSupply;
}
function mint(uint256 num) public {
require(num + counter<=MaxSupply , "Cant mint any more");
for(uint256 i=0;i<num;i++){
uint256 tokenId = counter;
_safeMint(msg.sender, tokenId);
counter++;
}
}
function transferFrom(address from, address to, uint256 tokenId) public override {
revert();
}
}
```
3.開發猜數字的合約(一個人設定,大家猜,有人猜中,就結束不讓其他人猜了)
```
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.20;
import "hardhat/console.sol";
contract w1h3 {
address private owner;
address private admin;
address public Winner;
bool public game_start = false;
int private number;
constructor(){
owner = msg.sender;
}
function getOwner()public view returns (address){
return owner;
}
function getAdmin()public view returns (address){
return admin;
}
function setAdmin(address i_admin)public{
require(msg.sender == owner , "u r not owner");
admin = i_admin;
}
function gameStart(int i_number)public{
require(msg.sender == admin , "u r not admin");
Winner = address(0);
number = i_number;
game_start = true;
}
function guessNum(int i_number)public{
require(game_start == true , "game offline");
if(i_number ==number){
console.log ("you win");
game_start = false;
Winner = msg.sender;
}
else{
console.log ("try again");
}
}
}
```
進階
1. 發行有盲盒機制的NFT!
**疑問點1**:我希望->抽中2張黑底可以拿回來換成5.png,到時候會burn掉2張nft去獨立mint一個限定版有角的NFTP[5.PNG]
我是不是不應該設計成從Solidity硬讀鏈以外的json->"bgcolor" ?但如果不這樣做,是不是只能在合約裡列出黑底的tokenId,人家要來換的時候再拿出來對比檢查?


```
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
contract Nft is ERC721 {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
bool private packed = true;
uint256 public maxSupply = 5;
address Admin = address(0);
string private packedURI = "ipfs://QmUkfvu8iWhsxRtAteZGLSDvDZnUQSvgrkxHD34TPPL3on/";
string private unpackedURI = "ipfs://QmX3bSTy4ankSQPBV1u516GCHN7eXHj3QVpgx3KymQwLHf/";
constructor() ERC721("KTC", "KC") {
Admin = msg.sender;
}
function safeMint(address to) internal {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(to, tokenId);
}
function mintNFT(uint256 _amount) public{
require(_tokenIdCounter.current()+_amount <= maxSupply, "sold out");
for(uint256 i=0;i<_amount;i++){
safeMint(msg.sender);
}
}
//盲盒開關
function switchRevealed(bool _status)public {
require(msg.sender == Admin,"admin only");
packed = _status;
}
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
//看開盒了沒
if (packed) {
return packedURI;
}
return string(abi.encodePacked(unpackedURI, Strings.toString(tokenId), ".json"));
}
}
```
進階2
[404error]