From a0dbb1debb9f85a52181a0a9c91469f76f37111c Mon Sep 17 00:00:00 2001 From: Christopher Canaday Date: Mon, 7 Apr 2025 17:31:48 -0400 Subject: [PATCH 1/4] transferable function changes --- contracts/VenueMint.sol | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/contracts/VenueMint.sol b/contracts/VenueMint.sol index 6b6b695..b651ce5 100644 --- a/contracts/VenueMint.sol +++ b/contracts/VenueMint.sol @@ -218,14 +218,15 @@ 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 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 From ccf20cccf5a64ceb35710fb200e4ac9913a1de54 Mon Sep 17 00:00:00 2001 From: CalebKornegay Date: Mon, 7 Apr 2025 17:57:31 -0400 Subject: [PATCH 2/4] Chwis your stuff doesn't workie, fixed the description stuff though, should cost less --- contracts/VenueMint.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/VenueMint.sol b/contracts/VenueMint.sol index b651ce5..4024bf1 100644 --- a/contracts/VenueMint.sol +++ b/contracts/VenueMint.sol @@ -36,7 +36,7 @@ contract VenueMint is ERC1155Holder, ERC1155 { 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 ids_to_description; uint256 last_id = 0; // The last id that we minted @@ -89,7 +89,7 @@ contract VenueMint is ERC1155Holder, ERC1155 { } id_to_transferable[i].exists = true; - ids_to_description[i] = description; + ids_to_description[i] = events.length; /* @@ -165,7 +165,7 @@ 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]; + return events[ids_to_description[id]].description; } // returns true if the description is available. false otherwise From 28217dfc674dc1a563a6b4fc940f5cbb0dd4b545 Mon Sep 17 00:00:00 2001 From: Christopher Canaday Date: Mon, 7 Apr 2025 19:42:41 -0400 Subject: [PATCH 3/4] added function to allow users to check their ticket transfer allow status --- contracts/VenueMint.sol | 158 ++++++++++++++++++++++++++++------------ 1 file changed, 113 insertions(+), 45 deletions(-) diff --git a/contracts/VenueMint.sol b/contracts/VenueMint.sol index 4024bf1..893cd5d 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,22 +29,30 @@ 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 => uint256) private ids_to_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_description; 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") { @@ -54,13 +62,24 @@ contract VenueMint is ERC1155Holder, ERC1155 { } // 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 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 + ); //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) { @@ -91,7 +112,6 @@ contract VenueMint is ERC1155Holder, ERC1155 { id_to_transferable[i].exists = true; ids_to_description[i] = events.length; - /* if(i < unique_seats) { amounts[i] = 1; @@ -107,12 +127,17 @@ 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; @@ -123,20 +148,29 @@ contract VenueMint is ERC1155Holder, ERC1155 { } 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 +184,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 +198,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) { + function get_event_description( + uint256 id + ) public view returns (string memory) { return events[ids_to_description[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 +223,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 +234,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 +250,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; @@ -222,6 +272,10 @@ contract VenueMint is ERC1155Holder, ERC1155 { 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."); @@ -235,17 +289,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 returns (bool) { 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 @@ -258,9 +326,9 @@ contract VenueMint is ERC1155Holder, ERC1155 { 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 +} From c34c0700a997f80b90a829d49bbac4350bc690cf Mon Sep 17 00:00:00 2001 From: Christopher Canaday Date: Tue, 8 Apr 2025 11:41:39 -0400 Subject: [PATCH 4/4] Removed unecessary returns. Changed variable name to be more accurate. Updated the test scripts for user-to-user transfer --- contracts/VenueMint.sol | 15 ++++++--------- test/VenueMint.ts | 3 ++- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/contracts/VenueMint.sol b/contracts/VenueMint.sol index 893cd5d..15c15e3 100644 --- a/contracts/VenueMint.sol +++ b/contracts/VenueMint.sol @@ -36,7 +36,7 @@ contract VenueMint is ERC1155Holder, ERC1155 { 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_description; + mapping(uint256 => uint256) private ids_to_events_index; uint256 last_id = 0; // The last id that we minted @@ -55,7 +55,7 @@ contract VenueMint is ERC1155Holder, ERC1155 { ); // 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); @@ -68,7 +68,7 @@ contract VenueMint is ERC1155Holder, ERC1155 { uint256 general_admission, uint256 unique_seats, uint256[] calldata costs - ) public returns (bool) { + ) public { require( costs.length == unique_seats + general_admission, "Must provide the same number of costs as general admission and unique seats." @@ -110,7 +110,7 @@ contract VenueMint is ERC1155Holder, ERC1155 { } id_to_transferable[i].exists = true; - ids_to_description[i] = events.length; + ids_to_events_index[i] = events.length; /* if(i < unique_seats) { @@ -144,7 +144,6 @@ contract VenueMint is ERC1155Holder, ERC1155 { _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) { @@ -201,7 +200,7 @@ contract VenueMint is ERC1155Holder, ERC1155 { function get_event_description( uint256 id ) public view returns (string memory) { - return events[ids_to_description[id]].description; + return events[ids_to_events_index[id]].description; } // returns true if the description is available. false otherwise @@ -292,7 +291,7 @@ contract VenueMint is ERC1155Holder, ERC1155 { function buy_ticket_from_user( address user, uint256 ticketid - ) public payable returns (bool) { + ) public payable { Transferable memory tmp = id_to_transferable[ticketid]; // we need to make sure this is a valid transfer @@ -322,8 +321,6 @@ contract VenueMint is ERC1155Holder, ERC1155 { id_to_transferable[ticketid].transferable = false; emit User_To_User_Transfer_Concluded(user, msg.sender); - - return true; } function supportsInterface( 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