diff --git a/contracts/VenueMint.sol b/contracts/VenueMint.sol index 6b6b695..15c15e3 100644 --- a/contracts/VenueMint.sol +++ b/contracts/VenueMint.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; @@ -29,38 +29,57 @@ contract VenueMint is ERC1155Holder, ERC1155 { address private owner; // Deployer of contract (us) address private self; // The address of the contract (self) - mapping (string => address payable) private event_to_vendor; // Mapping event descriptions to vendor wallets - mapping (uint256 => uint256) private ticket_costs; // Mapping nft ids to cost + mapping(string => address payable) private event_to_vendor; // Mapping event descriptions to vendor wallets + mapping(uint256 => uint256) private ticket_costs; // Mapping nft ids to cost // mapping nft ids to their original costs (ticket_costs gets zero'd on purchase) - mapping (uint256 => uint256) private original_ticket_costs; - mapping (string => Ids) private event_to_ids; // Mapping event descriptions to NFT ids - // Mapping ticket id to whether they are allowed to be transferred to another user - mapping (uint256 => Transferable) private id_to_transferable; - mapping (uint256 => string) private ids_to_description; // Mapping ticket id to event description + mapping(uint256 => uint256) private original_ticket_costs; + mapping(string => Ids) private event_to_ids; // Mapping event descriptions to NFT ids + // Mapping ticket id to whether they are allowed to be transferred to another user + mapping(uint256 => Transferable) private id_to_transferable; + mapping(uint256 => uint256) private ids_to_events_index; uint256 last_id = 0; // The last id that we minted Event[] private events; - event Event_Commencement(address indexed from, string description, string venue_URI, uint256 capacity); + event Event_Commencement( + address indexed from, + string description, + string venue_URI, + uint256 capacity + ); event Buy_Ticket_Event(string description, uint256 count); - event User_To_User_Transfer_Concluded(address indexed seller, address indexed buyer); + event User_To_User_Transfer_Concluded( + address indexed seller, + address indexed buyer + ); // Set the owner to the deployer and self to the address of the contract - constructor() ERC1155("https://onlytickets.co/api/tokens/{id}.json") { + constructor() ERC1155("https://client.dev.opentix.co/api/tokens/{id}.json") { owner = msg.sender; self = address(this); //console.log("Contract address is ", self, " and owner address is", owner); } // Create a new event check the costs, emit an event being made - function create_new_event(string calldata description, string calldata vendor_url, - uint256 general_admission, uint256 unique_seats, - uint256[] calldata costs) public returns (bool) { - require(costs.length == unique_seats + general_admission, - "Must provide the same number of costs as general admission and unique seats."); - - emit Event_Commencement(msg.sender, description, vendor_url, general_admission + unique_seats); + function create_new_event( + string calldata description, + string calldata vendor_url, + uint256 general_admission, + uint256 unique_seats, + uint256[] calldata costs + ) public { + require( + costs.length == unique_seats + general_admission, + "Must provide the same number of costs as general admission and unique seats." + ); + + emit Event_Commencement( + msg.sender, + description, + vendor_url, + general_admission + unique_seats + ); //console.log("Description is %s", description); //console.log("Venue URL is %s", from); @@ -74,7 +93,9 @@ contract VenueMint is ERC1155Holder, ERC1155 { // Set the ids and the amounts of each along with the cost of each being minted uint256[] memory ids = new uint256[](unique_seats + general_admission); - uint256[] memory amounts = new uint256[](unique_seats + general_admission); + uint256[] memory amounts = new uint256[]( + unique_seats + general_admission + ); uint256 i = last_id; for (; i < last_id + ids.length; ++i) { @@ -89,8 +110,7 @@ contract VenueMint is ERC1155Holder, ERC1155 { } id_to_transferable[i].exists = true; - ids_to_description[i] = description; - + ids_to_events_index[i] = events.length; /* if(i < unique_seats) { @@ -107,36 +127,49 @@ contract VenueMint is ERC1155Holder, ERC1155 { // Track the vendor wallet so they can be paid when someone buys a ticket to their event // Save the event to events event_to_vendor[description] = payable(msg.sender); - events.push(Event({ description:description, count: general_admission + unique_seats})); + events.push( + Event({ + description: description, + count: general_admission + unique_seats + }) + ); // keep track of the NFT ids for the event Ids memory tmp; tmp.min = last_id; - tmp.max = i-1; + tmp.max = i - 1; tmp.exists = true; event_to_ids[description] = tmp; _mintBatch(self, ids, amounts, ""); // Keep up with the last nft we minted; last_id = i; - return true; } function get_events() public view returns (string[] memory) { - string[] memory ret = new string[](events.length > 100 ? 100 : events.length); + string[] memory ret = new string[]( + events.length > 100 ? 100 : events.length + ); uint256 j = 0; for (uint256 i = 0; i < events.length; ++i) { if (events[i].count > 0) { - ret[j++] = string(abi.encodePacked(events[i].description, - " Capacity is ", Strings.toString(events[i].count))); + ret[j++] = string( + abi.encodePacked( + events[i].description, + " Capacity is ", + Strings.toString(events[i].count) + ) + ); } } return ret; } // returns a list of all valid NFT ids for the event - function get_event_ids(string calldata description) public view returns (uint256[] memory, Ids memory) { + function get_event_ids( + string calldata description + ) public view returns (uint256[] memory, Ids memory) { Ids memory tmp = event_to_ids[description]; uint256 count = 0; @@ -150,7 +183,7 @@ contract VenueMint is ERC1155Holder, ERC1155 { } } - uint256[] memory result = new uint256[](count); + uint256[] memory result = new uint256[](count); uint256 j = 0; for (uint256 i = tmp.min; i <= tmp.max; i++) { if (ticket_costs[i] != 0) { @@ -164,17 +197,23 @@ contract VenueMint is ERC1155Holder, ERC1155 { } // get the event description with the ticket id - function get_event_description(uint256 id) public view returns (string memory) { - return ids_to_description[id]; + function get_event_description( + uint256 id + ) public view returns (string memory) { + return events[ids_to_events_index[id]].description; } // returns true if the description is available. false otherwise - function is_description_available(string calldata description) public view returns (bool) { + function is_description_available( + string calldata description + ) public view returns (bool) { return !event_to_ids[description].exists; } // Give the cost of tickets so that we can pass that into value field on frontend - function get_cost_for_tickets(uint256[] calldata ids) public view returns (uint256) { + function get_cost_for_tickets( + uint256[] calldata ids + ) public view returns (uint256) { uint256 total_cost = 0; for (uint256 i = 0; i < ids.length; ++i) { total_cost += ticket_costs[ids[i]]; @@ -183,8 +222,10 @@ contract VenueMint is ERC1155Holder, ERC1155 { } // Enable users to buy tickets (NFTs) - function buy_tickets(string calldata event_description, uint256[] calldata ids) payable public - returns (bool, uint256) { + function buy_tickets( + string calldata event_description, + uint256[] calldata ids + ) public payable returns (bool, uint256) { // Get the total cost of each tickets uint256 total_cost = 0; for (uint256 i = 0; i < ids.length; ++i) { @@ -192,9 +233,15 @@ contract VenueMint is ERC1155Holder, ERC1155 { } // Check if they are able to buy those tickets and that they have enough money - require (total_cost > 0, "You are attempting to buy unavailable tickets."); - require(msg.value >= total_cost, "You do not have enough money to purchase the desired tickets."); - + require( + total_cost > 0, + "You are attempting to buy unavailable tickets." + ); + require( + msg.value >= total_cost, + "You do not have enough money to purchase the desired tickets." + ); + // Buy one since they're NFTs uint256[] memory values = new uint256[](ids.length); for (uint256 i = 0; i < ids.length; ++i) { @@ -202,13 +249,15 @@ contract VenueMint is ERC1155Holder, ERC1155 { } // Transfer the money to the vendor - (bool success, ) = event_to_vendor[event_description].call{value:total_cost}(""); + (bool success, ) = event_to_vendor[event_description].call{ + value: total_cost + }(""); require(success, "transfer to vender failed."); // Transfer the tickets to the user _safeBatchTransferFrom(self, msg.sender, ids, values, ""); emit Buy_Ticket_Event(event_description, ids.length); - + // 0 out the costs so that we can't double sell tickets for (uint256 i = 0; i < ids.length; ++i) { ticket_costs[ids[i]] = 0; @@ -218,14 +267,19 @@ contract VenueMint is ERC1155Holder, ERC1155 { } // this enables the input user to transfer the callers tickets - function allow_user_to_user_ticket_transfer(uint256 ticketid) public returns (bool) { + function allow_user_to_user_ticket_transfer() public { + setApprovalForAll(self, true); + } + + function check_ticket_transfer_permission() public view returns (bool) { + return isApprovedForAll(msg.sender, self); + } + + function allow_ticket_to_be_transfered(uint256 ticketid) public { Transferable memory tmp = id_to_transferable[ticketid]; require(tmp.exists, "The ticket id provided is not valid."); id_to_transferable[ticketid].transferable = true; - - setApprovalForAll(self, true); - return true; } // disables the contracts control of the senders tokens @@ -234,17 +288,31 @@ contract VenueMint is ERC1155Holder, ERC1155 { } // this should be called buy the purchaser of the ticket - function buy_ticket_from_user(address user, uint256 ticketid) payable public returns (bool) { + function buy_ticket_from_user( + address user, + uint256 ticketid + ) public payable { Transferable memory tmp = id_to_transferable[ticketid]; // we need to make sure this is a valid transfer require(tmp.exists, "The ticket id provided is not valid."); - require(isApprovedForAll(user, self), "The seller has not authorized a transfer."); - require(tmp.transferable, "This ticket id provided is not transferable."); - require(msg.value >= original_ticket_costs[ticketid],"You did not send enough money to purchase the ticket."); + require( + isApprovedForAll(user, self), + "The seller has not authorized a transfer." + ); + require( + tmp.transferable, + "This ticket id provided is not transferable." + ); + require( + msg.value >= original_ticket_costs[ticketid], + "You did not send enough money to purchase the ticket." + ); // send the money to the user - (bool success, ) = user.call{value:original_ticket_costs[ticketid]}(""); + (bool success, ) = user.call{value: original_ticket_costs[ticketid]}( + "" + ); require(success, "Failed to pay the user you are purchasing from."); // transfer the nft to the purchaser @@ -253,13 +321,11 @@ contract VenueMint is ERC1155Holder, ERC1155 { id_to_transferable[ticketid].transferable = false; emit User_To_User_Transfer_Concluded(user, msg.sender); - - return true; } - function supportsInterface(bytes4 interfaceId) public view virtual override(ERC1155, ERC1155Holder) - returns (bool) { + function supportsInterface( + bytes4 interfaceId + ) public view virtual override(ERC1155, ERC1155Holder) returns (bool) { return super.supportsInterface(interfaceId); } - -} \ No newline at end of file +} diff --git a/test/VenueMint.ts b/test/VenueMint.ts index c240c71..d8ba309 100644 --- a/test/VenueMint.ts +++ b/test/VenueMint.ts @@ -169,7 +169,8 @@ describe("VenueMint", function () { // buy the tickets and give the contract permission to control the holders tokens const resp = await holder_instance.buy_tickets("test", [0], {value: ethers.parseEther("1")}); - const resp1 = await holder_instance.allow_user_to_user_ticket_transfer(0); + const resp1 = await holder_instance.allow_user_to_user_ticket_transfer(); + const resp11 = await holder_instance.allow_ticket_to_be_transfered(0); // variable to check that we removed the contracts ability to control our tokens // a filter that allows us to only execute the function based on the holder and purchaser address