---
# System prepended metadata

title: 5/26 +5/28 討論
tags: [畢專]

---

###### tags: `畢專`
# 5/26 +5/28 討論

 ### 新增活動+拿掉ticket id + price
```
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract TicketContract is ERC1155, Ownable {
    using Counters for Counters.Counter;

    struct Ticket {
        address owner; // 擁有者地址
        uint256 eventId; // 活動ID
        uint256 quantity; // 數量（每個NFT代表一張票）
        uint256 price; // 價格
        uint256 startTime; // 活動開始時間
        bool refunded; // 是否已退款
        bool isUsed; // 是否已使用
    }

    mapping(address => mapping(address => bool)) private _operatorApprovals; //為了使 NFT 可以進行轉移而用於追蹤已授權的操作者。
    mapping(uint256 => Ticket) public tickets; // 票ID映射到票的詳細信息
    Counters.Counter private ticketIdCounter; // 票ID計數器
    uint256 public constant MAX_SUPPLY = 500; // 最大供應量
    uint256 public constant MAX_PER_MINT = 1; // 每次購買的最大數量
    uint256 public constant REFUND_PERCENT = 80; // 退款百分比

    event TicketMinted(uint256 indexed ticketId, address indexed owner); // 票被鑄造時觸發的事件
    event TicketBurned(uint256 indexed ticketId); // 票被銷毀時觸發的事件
    event TicketTransferred(uint256 indexed ticketId, address indexed from, address indexed to); // 票被轉移時觸發的事件

    constructor() ERC1155("") {}

    // 鑄造票
    function mintTicket(uint256 eventId, uint256 quantity, uint256 price) external payable {
        require(quantity <= MAX_PER_MINT, "Exceeds maximum per mint");
        require(ticketIdCounter.current() + quantity <= MAX_SUPPLY, "Exceeds maximum supply");
        require(msg.value == price * quantity, "Insufficient payment");

        for (uint256 i = 0; i < quantity; i++) {
            uint256 ticketId = ticketIdCounter.current();

            tickets[ticketId] = Ticket({
                owner: msg.sender,
                eventId: eventId,
                quantity: 1,
                price: price,
                startTime: block.timestamp,
                refunded: false,
                isUsed: false
            });

            _mint(msg.sender, ticketId, 1, "");
            ticketIdCounter.increment();

            emit TicketMinted(ticketId, msg.sender);
        }
    }

    // 銷毀票
    function burnTicket(uint256 ticketId) external {
        require(_msgSender() == tickets[ticketId].owner, "Only ticket owner can burn the ticket");
        require(!tickets[ticketId].isUsed, "Cannot burn a used ticket");
            delete tickets[ticketId];

    _burn(_msgSender(), ticketId, 1);

    emit TicketBurned(ticketId);
}

// 轉移票
    function transferTicket(address to, uint256 ticketId) external {
        require(_msgSender() == tickets[ticketId].owner, "Only ticket owner can transfer the ticket");
        require(!tickets[ticketId].isUsed, "Cannot transfer a used ticket");

        tickets[ticketId].owner = to;

        safeTransferFrom(_msgSender(), to, ticketId, 1, "");

        emit TicketTransferred(ticketId, _msgSender(), to);
    }

// 活動結束後銷毀所有票
function burnTicketsAfterEvent(uint256 eventId) external onlyOwner {
    require(block.timestamp > tickets[eventId].startTime, "Event has not ended yet");

    for (uint256 i = 0; i < ticketIdCounter.current(); i++) {
        if (tickets[i].eventId == eventId) {
            _burn(tickets[i].owner, i, tickets[i].quantity);

            emit TicketBurned(i);
        }
    }
}

// 退款
function refund(uint256 ticketId) external {
    require(tickets[ticketId].owner == msg.sender, "Not the ticket owner");
    require(block.timestamp < tickets[ticketId].startTime, "Refund period has ended");

    if (!tickets[ticketId].refunded) {
        uint256 refundAmount = (tickets[ticketId].price * REFUND_PERCENT) / 100;
        uint256 feeAmount = tickets[ticketId].price - refundAmount;

        tickets[ticketId].refunded = true;
        payable(tickets[ticketId].owner).transfer(refundAmount);
        payable(owner()).transfer(feeAmount);

        _burn(msg.sender, ticketId, 1);

        emit TicketBurned(ticketId);
    }
}

    // 設置票務系統中的NFT的URI
    function setURI(string memory newUri) public onlyOwner {
        _setURI(newUri);
    }

    // 查詢總票數，展示網頁中的現在票務銷售情況
    function getTotalTickets() external view returns (uint256) {
        return ticketIdCounter.current();
    }

    // 檢查合約是否支持ERC1155介面
    function supportsInterface(bytes4 interfaceId) public view override(ERC1155) returns (bool) {
        return super.supportsInterface(interfaceId);
    }

    // 提取合約中的資金
    function withdraw() external onlyOwner {
        uint256 balance = address(this).balance;
        payable(owner()).transfer(balance);
    }

    // 獲取活動詳細信息
    function getEvent(uint256 eventId) external view returns (
        uint256 id,
        uint256 totalTickets,
        uint256 ticketPrice,
        uint256 startTime
    ) {
        Ticket storage ticket = tickets[eventId];
        require(ticket.owner != address(0), "Event does not exist");

        return (
            ticket.eventId,
            ticketIdCounter.current(),
            ticket.price,
            ticket.startTime
        );
    }
}
```


5/28

### event struct(mintTicket&refund function以使用新的events映射，並在burnTicketsAfterEvent函數中修改了判斷活動是否結束) + 改成tokenId


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

import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract TicketContract is ERC1155, Ownable {
    using Counters for Counters.Counter;

    struct Event {
        string name; // 活動名稱
        uint256 price; // 活動票價
        uint256 capacity; // 人數限制
        string eventType; // 活動類型
        bool oneTicketPerPerson; // 是否一人限購一張
        uint256 startTime; // 活動開始時間
        uint256 endTime; // 活動結束時間
    }
    mapping(uint256 => Event) public events;

    struct Ticket {
        address owner; // 擁有者地址
        uint256 eventId; // 活動ID
        uint256 quantity; // 數量（每個NFT代表一張票）
        uint256 price; // 價格
        uint256 startTime; // 活動開始時間
        bool refunded; // 是否已退款
        bool isUsed; // 是否已使用
    }
    mapping(uint256 => Ticket) public tickets; // 票ID映射到票的詳細信息
    mapping(address => mapping(uint256 => bool)) public addressHasPurchased; // 地址是否已購買特定活動的票
    Counters.Counter private tokenIdCounter; // tokenId計數器
    uint256 public constant MAX_SUPPLY = 500; // 最大供應量
    uint256 public constant MAX_PER_MINT = 1; // 每次購買的最大數量
    uint256 public constant REFUND_PERCENT = 80; // 退款百分比

    event TicketMinted(uint256 indexed tokenId, address indexed owner); // 票被鑄造時觸發的事件
    event TicketBurned(uint256 indexed tokenId); // 票被銷毀時觸發的事件
    event TicketTransferred(uint256 indexed tokenId, address indexed from, address indexed to); // 票被轉移時觸發的事件

    constructor() ERC1155("") {}

    // 新增活動種類
    function addEvent(
        uint256 eventId,
        string memory name,
        uint256 price,
        uint256 capacity,
        string memory eventType,
        bool oneTicketPerPerson,
        uint256 startTime,
        uint256 endTime
    ) external onlyOwner {
        events[eventId] = Event({
            name: name,
            price: price,
            capacity: capacity,
            eventType: eventType,
            oneTicketPerPerson: oneTicketPerPerson,
            startTime: startTime,
            endTime: endTime
        });
    }

    // 鑄造票
    function mintTicket(uint256 eventId, uint256 quantity) external payable {
        require(quantity <= MAX_PER_MINT, "Exceeds maximum per mint");
        require(tokenIdCounter.current() + quantity <= MAX_SUPPLY, "Exceeds maximum supply");
        require(msg.value == events[eventId].price * quantity, "Insufficient payment");
        require(block.timestamp < events[eventId].endTime, "Event has already ended");
            uint256 tokenId = tokenIdCounter.current();

    require(events[eventId].oneTicketPerPerson && !addressHasPurchased[msg.sender][eventId], "One ticket per person rule violated");

    require(quantity <= events[eventId].capacity, "Exceeds event capacity");

    tickets[tokenId] = Ticket({
        owner: msg.sender,
        eventId: eventId,
        quantity: quantity,
        price: events[eventId].price,
        startTime: events[eventId].startTime,
        refunded: false,
        isUsed: false
    });

    _mint(msg.sender, tokenId, quantity, "");
    tokenIdCounter.increment();

    // Mark the address as having purchased tickets for the specific event
    addressHasPurchased[msg.sender][eventId] = true;

    emit TicketMinted(tokenId, msg.sender);
}

    // 轉移票
    function transferTicket(address to, uint256 tokenId) external {
        require(_msgSender() == tickets[tokenId].owner, "Only ticket owner can transfer the ticket");
        require(!tickets[tokenId].isUsed, "Cannot transfer a used ticket");
        require(block.timestamp < tickets[tokenId].startTime, "Ticket transfer not allowed after event start time");

        tickets[tokenId].owner = to;

        safeTransferFrom(_msgSender(), to, tokenId, tickets[tokenId].quantity, "");

        emit TicketTransferred(tokenId, _msgSender(), to);
    }

    // 活動結束後銷毀所有票
    function burnTicketsAfterEvent(uint256 eventId) external onlyOwner {
        require(block.timestamp > events[eventId].endTime, "Event has not ended yet");

        for (uint256 i = 0; i < tokenIdCounter.current(); i++) {
            if (tickets[i].eventId == eventId) {
                _burn(tickets[i].owner, i, tickets[i].quantity);

                emit TicketBurned(i);
            }
        }
    }

    // 退款
    function refund(uint256 tokenId) external {
        require(tickets[tokenId].owner == msg.sender, "Not the ticket owner");
        require(block.timestamp < events[tickets[tokenId].eventId].startTime, "Refund period has ended");

        if (!tickets[tokenId].refunded) {
            uint256 refundAmount = (tickets[tokenId].price * REFUND_PERCENT) / 100;
            uint256 feeAmount = tickets[tokenId].price - refundAmount;

            tickets[tokenId].refunded = true;
            payable(tickets[tokenId].owner).transfer(refundAmount);
            payable(owner()).transfer(feeAmount);

            _burn(msg.sender, tokenId, tickets[tokenId].quantity);

            emit TicketBurned(tokenId);
        }
    }

    // 設置票務系統中的NFT的URI
    function setURI(string memory newUri) public onlyOwner {
        _setURI(newUri);
    }

    // 查詢總票數，展示網頁中的現在票務銷售情況
    function getTotalTickets() external view returns (uint256) {
        return tokenIdCounter.current();
    }

    // 檢查合約是否支持ERC1155介面
    function supportsInterface(bytes4 interfaceId) public view override(ERC1155) returns (bool) {
        return super.supportsInterface(interfaceId);
    }

    // 提取合約中的資金
    function withdraw() external onlyOwner {
        uint256 balance = address(this).balance;
        payable(owner()).transfer(balance);
    }
}


```


### 點到使用者
address 對到token

要怎麼丟到前台
