From f6f95608655af423689f14cda6567dd146e533ef Mon Sep 17 00:00:00 2001 From: Christopher Canaday Date: Sun, 27 Apr 2025 15:28:27 -0400 Subject: [PATCH 1/5] Optimizations to storage --- contracts/VenueMint.sol | 203 ++++++++++++++++++++-------------------- test/VenueMint.ts | 200 +++++++++++++++++++-------------------- 2 files changed, 204 insertions(+), 199 deletions(-) diff --git a/contracts/VenueMint.sol b/contracts/VenueMint.sol index 855995f..aae9a09 100644 --- a/contracts/VenueMint.sol +++ b/contracts/VenueMint.sol @@ -7,11 +7,6 @@ import "@openzeppelin/contracts/utils/Strings.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; // import "hardhat/console.sol"; -struct Event { - uint256 count; - string description; -} - // holds the minimum and maximum ids for that event struct Ids { // both inclusive @@ -20,8 +15,16 @@ struct Ids { bool exists; } -struct Transferable { - bool transferable; +struct Event { + uint256 count; + string description; + Ids ids; + address vendor_wallet; + uint256 ticket_cost; +} + +struct EventsIndex { + uint256 index; bool exists; } @@ -29,14 +32,14 @@ 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 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 nft ids to cost + // mapping(uint256 => uint256) private ticket_costs; + // 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; + mapping(uint256 => bool) private id_to_transferable; + + // map description to the event + mapping(string => EventsIndex) private description_to_events_index; uint256 last_id = 0; // The last id that we minted @@ -63,18 +66,30 @@ contract VenueMint is ERC1155Holder, ERC1155 { //console.log("Contract address is ", self, " and owner address is", owner); } + function get_ticket_cost(uint256 id) view private returns (uint256) { + for (uint256 i = 0; i < events.length; i++) { + Ids memory tmp = events[i].ids; + + if (id >= tmp.min && id <= tmp.max) { + return events[i].ticket_cost; + } + } + + return 0; + } + // 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 + uint256 cost ) public { - require( - costs.length == unique_seats + general_admission, - "Must provide the same number of costs as general admission and unique seats." - ); + // 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, @@ -83,16 +98,6 @@ contract VenueMint is ERC1155Holder, ERC1155 { general_admission + unique_seats ); - //console.log("Description is %s", description); - //console.log("Venue URL is %s", from); - //console.log("General admission is %d", general_admission); - //console.log("Unique seats is %d", unique_seats); - - /* - uint256[] memory ids = new uint256[](unique_seats + 1); - uint256[] memory amounts = new uint256[](unique_seats + 1); - */ // Uncomment this if we want to try semi-fungible tickets - // 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[]( @@ -103,46 +108,34 @@ contract VenueMint is ERC1155Holder, ERC1155 { for (; i < last_id + ids.length; ++i) { ids[i - last_id] = i; amounts[i - last_id] = 1; - if (i < unique_seats) { - ticket_costs[i] = costs[i - last_id]; - original_ticket_costs[i] = costs[i - last_id]; - } else { - ticket_costs[i] = costs[costs.length - 1]; - original_ticket_costs[i] = costs[costs.length - 1]; - } - - id_to_transferable[i].exists = true; - ids_to_events_index[i] = events.length; + // if (i < unique_seats) { + // ticket_costs[i] = costs[i - last_id]; + // } else { + // ticket_costs[i] = costs[costs.length - 1]; + // } + } - /* - if(i < unique_seats) { - amounts[i] = 1; - } else { - amounts[i] = general_admission; - } - */ // Uncomment this if we want to try semi-fungible tickets + // keep track of the NFT ids for the event + Ids memory tmp; + tmp.min = last_id; + tmp.max = i - 1; + tmp.exists = true; - // console.log("ids[%d] = %d", i, ids[i]); - // console.log("amounts[%d] = %d", i, amounts[i]); - } + EventsIndex memory tmp2; + tmp2.exists = true; + tmp2.index = events.length; - // 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); + description_to_events_index[description] = tmp2; events.push( Event({ description: description, - count: general_admission + unique_seats + count: general_admission + unique_seats, + ids: tmp, + vendor_wallet: payable(msg.sender), + ticket_cost: cost }) ); - // keep track of the NFT ids for the event - Ids memory tmp; - tmp.min = last_id; - 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; @@ -172,15 +165,18 @@ contract VenueMint is ERC1155Holder, ERC1155 { function get_event_ids( string calldata description ) public view returns (uint256[] memory, Ids memory) { - Ids memory tmp = event_to_ids[description]; - uint256 count = 0; + EventsIndex memory tmp2 = description_to_events_index[description]; // check that there is a valid description - require(tmp.exists, "Please provide a description for a valid event."); + require(tmp2.exists, "Please provide a description for a valid event."); + + Ids memory tmp = events[description_to_events_index[description].index] + .ids; + uint256 count = 0; // figure out how big our array needs to be for (uint256 i = tmp.min; i <= tmp.max; i++) { - if (ticket_costs[i] != 0) { + if (balanceOf(self, i) > 0) { count++; } } @@ -188,8 +184,7 @@ contract VenueMint is ERC1155Holder, ERC1155 { uint256[] memory result = new uint256[](count); uint256 j = 0; for (uint256 i = tmp.min; i <= tmp.max; i++) { - if (ticket_costs[i] != 0) { - //console.log(i); + if (balanceOf(self, i) > 0) { result[j] = i; j++; } @@ -202,14 +197,21 @@ contract VenueMint is ERC1155Holder, ERC1155 { function get_event_description( uint256 id ) public view returns (string memory) { - return events[ids_to_events_index[id]].description; + for (uint256 i = 0; i < events.length; i++) { + Ids memory tmp = events[i].ids; + + if (id >= tmp.min && id <= tmp.max) { + return events[i].description; + } + } + return ""; } // returns true if the description is available. false otherwise function is_description_available( string calldata description ) public view returns (bool) { - return !event_to_ids[description].exists; + return !description_to_events_index[description].exists; } // Give the cost of tickets so that we can pass that into value field on frontend @@ -218,7 +220,7 @@ contract VenueMint is ERC1155Holder, ERC1155 { ) public view returns (uint256) { uint256 total_cost = 0; for (uint256 i = 0; i < ids.length; ++i) { - total_cost += ticket_costs[ids[i]]; + total_cost += get_ticket_cost(ids[i]); } return total_cost; } @@ -228,10 +230,22 @@ contract VenueMint is ERC1155Holder, ERC1155 { string calldata event_description, uint256[] calldata ids ) public payable returns (bool, uint256) { + // Make sure its a real event + require( + description_to_events_index[event_description].exists, + "Please provide a description for a valid event." + ); + // Get the total cost of each tickets uint256 total_cost = 0; for (uint256 i = 0; i < ids.length; ++i) { - total_cost += ticket_costs[ids[i]]; + // Make sure the contract currently has these tickets + require( + balanceOf(self, ids[i]) > 0, + "One of these tickets has already been sold." + ); + + total_cost += get_ticket_cost(ids[i]); } // Check if they are able to buy those tickets and that they have enough money @@ -251,20 +265,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, ) = events[ + description_to_events_index[event_description].index + ].vendor_wallet.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; - } - return (true, total_cost); } @@ -277,32 +286,30 @@ contract VenueMint is ERC1155Holder, ERC1155 { return isApprovedForAll(msg.sender, self); } - function check_ticket_transferable(uint256 ticketid) public view returns (bool) { - Transferable memory tmp = id_to_transferable[ticketid]; - require(tmp.exists, "The ticket id provided is not valid."); - return tmp.transferable; + function check_ticket_transferable( + uint256 ticketid + ) public view returns (bool) { + return id_to_transferable[ticketid]; } 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."); + require(ticketid < last_id, "The ticket id provided is not valid."); require( balanceOf(msg.sender, ticketid) > 0, "Can't allow ticket transfer for a ticket you do not own." ); - id_to_transferable[ticketid].transferable = true; + id_to_transferable[ticketid] = true; } function disallow_ticket_to_be_transfered(uint256 ticketid) public { - Transferable memory tmp = id_to_transferable[ticketid]; - require(tmp.exists, "The ticket id provided is not valid."); + require(ticketid < last_id, "The ticket id provided is not valid."); require( balanceOf(msg.sender, ticketid) > 0, "Can't disallow ticket transfer for a ticket you do not own." ); - id_to_transferable[ticketid].transferable = false; + id_to_transferable[ticketid] = false; } // disables the contracts control of the senders tokens @@ -315,37 +322,35 @@ contract VenueMint is ERC1155Holder, ERC1155 { address user, uint256 ticketid ) public payable { - Transferable memory tmp = id_to_transferable[ticketid]; + bool 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(ticketid < last_id, "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(tmp, "This ticket id provided is not transferable."); require( balanceOf(user, ticketid) > 0, "Requested seller does not own the ticket." ); + + uint256 cost = get_ticket_cost(ticketid); + require( - msg.value >= original_ticket_costs[ticketid], + msg.value >= cost, "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: cost}(""); require(success, "Failed to pay the user you are purchasing from."); // transfer the nft to the purchaser _safeTransferFrom(user, msg.sender, ticketid, 1, ""); - id_to_transferable[ticketid].transferable = false; + id_to_transferable[ticketid] = false; emit User_To_User_Transfer_Concluded(user, msg.sender); } diff --git a/test/VenueMint.ts b/test/VenueMint.ts index d8ba309..77bf383 100644 --- a/test/VenueMint.ts +++ b/test/VenueMint.ts @@ -47,7 +47,7 @@ describe("VenueMint", function () { // this checks that the contract owns the nft after creation it("can create an nft", async () => { const contract = await loadFixture(deployOne); - await contract.create_new_event("test", "0xblahblahblah", 1, 0, [5]) + await contract.create_new_event("test", "0xblahblahblah", 1, 0, 5) expect(await contract.balanceOfBatch([await contract.getAddress()], [0])).to.eql([1n]) }) @@ -72,7 +72,7 @@ describe("VenueMint", function () { ethers.provider.send("hardhat_setBalance", [userAddress, "0xFFFFFFFFFFFFFFFFFFFFF"]) // create the event - const tmp = await vendor_contract_instance.create_new_event("test", address, 1, 0, [5000]) + const tmp = await vendor_contract_instance.create_new_event("test", address, 1, 0, 5000) // attach the contract to the user wallet // this means when we call the contracts functions the @@ -90,7 +90,7 @@ describe("VenueMint", function () { it("can create multiple nfts", async () => { const contract = await loadFixture(deployOne); const contract_address = await contract.getAddress(); - await contract.create_new_event("test", contract_address, 2, 0, [5, 5]); + await contract.create_new_event("test", contract_address, 2, 0, 5); expect(await contract.balanceOfBatch([contract_address, contract_address], [0,1])).to.eql([1n,1n]) }) @@ -105,7 +105,7 @@ describe("VenueMint", function () { for(let i = 1; i <= max; i++) { // create the events - await contract.create_new_event(`test ${i*base}`, contract_address, i*base, 0, Array(i*base).fill(5)); + await contract.create_new_event(`test ${i*base}`, contract_address, i*base, 0, 5); // check that the contract owns all the events expect(await contract.balanceOfBatch(Array(i*base).fill(contract_address), Array.from({length: i*base}, (_, i) => i + total_so_far))).to.eql(Array(i*base).fill(1n)); @@ -116,7 +116,7 @@ describe("VenueMint", function () { it("can get the ids of an event", async () => { const contract = await loadFixture(deployOne); - const tmp = await contract.create_new_event("test", "0xblahblah", 5, 0, [5,5,5,5,5]); + const tmp = await contract.create_new_event("test", "0xblahblah", 5, 0, 5); // check that it returns properly for a valid and non valid event expect((await contract.get_event_ids("test"))[0]).to.eql(Array(0n,1n,2n,3n,4n)); @@ -129,7 +129,7 @@ describe("VenueMint", function () { const user_address = await user.getAddress(); ethers.provider.send("hardhat_setBalance", [user_address, "0xFFFFFFFFFFFFFFFFFFFFF"]) - await contract.create_new_event("test", "0xblahblah", 5, 0, [5,5,5,5,5]); + await contract.create_new_event("test", "0xblahblah", 5, 0, 5); const user_contract_instance = contract.connect(user); await user_contract_instance.buy_tickets("test", [0], {value: ethers.parseEther("1")}); @@ -144,7 +144,7 @@ describe("VenueMint", function () { expect(tmp).to.equal(true); - await contract.create_new_event("test", "tme", 1, 0, [1]); + await contract.create_new_event("test", "tme", 1, 0, 1); expect(await contract.is_description_available("test")).to.equal(false); }) @@ -165,7 +165,7 @@ describe("VenueMint", function () { // make the holder instance and create the event const holder_instance = init_contract.connect(nftholderwallet); - const tmp = await holder_instance.create_new_event("test", "cool beans", 1, 0, [2000]); + const tmp = await holder_instance.create_new_event("test", "cool beans", 1, 0, 2000); // 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")}); @@ -233,7 +233,7 @@ describe("VenueMint", function () { ethers.provider.send("hardhat_setBalance", [userAddress, "0xFFFFFFFFFFFFFFFFFFFFF"]) // create the event - const tmp = await vendor_contract_instance.create_new_event("test", address, 1, 0, [ticket_cost]); + const tmp = await vendor_contract_instance.create_new_event("test", address, 1, 0, ticket_cost); // attach the contract to the user wallet // this means when we call the contracts functions the @@ -275,7 +275,7 @@ describe("VenueMint", function () { ethers.provider.send("hardhat_setBalance", [userAddress, "0xFFFFFFFFFFFFFFFFFFFFF"]) // create the event - const tmp = await vendor_contract_instance.create_new_event("test", address, 2, 0, [ticket_cost, ticket_cost]); + const tmp = await vendor_contract_instance.create_new_event("test", address, 2, 0, ticket_cost); // attach the contract to the user wallet // this means when we call the contracts functions the @@ -317,7 +317,7 @@ describe("VenueMint", function () { ethers.provider.send("hardhat_setBalance", [userAddress, "0xFFFFFFFFFFFFFFFFFFFFF"]) // create the event - const tmp = await vendor_contract_instance.create_new_event("test", address, 2, 0, [ticket_cost, ticket_cost]); + const tmp = await vendor_contract_instance.create_new_event("test", address, 2, 0, ticket_cost); // attach the contract to the user wallet // this means when we call the contracts functions the @@ -367,7 +367,7 @@ describe("VenueMint", function () { ethers.provider.send("hardhat_setBalance", [userAddress2, "0xFFFFFFFFFFFFFFFFFFFFF"]) // create the event - const tmp = await vendor_contract_instance.create_new_event("test", address, 2, 0, [ticket_cost, ticket_cost]); + const tmp = await vendor_contract_instance.create_new_event("test", address, 2, 0, ticket_cost); // attach the contract to the user wallet // this means when we call the contracts functions the @@ -420,7 +420,7 @@ describe("VenueMint", function () { ethers.provider.send("hardhat_setBalance", [userAddress2, "0xFFFFFFFFFFFFFFFFFFFFF"]) // create the event - const tmp = await vendor_contract_instance.create_new_event("test", address, 4, 0, [ticket_cost, ticket_cost, ticket_cost, ticket_cost]); + const tmp = await vendor_contract_instance.create_new_event("test", address, 4, 0, ticket_cost); // attach the contract to the user wallet // this means when we call the contracts functions the @@ -472,7 +472,7 @@ describe("VenueMint", function () { ethers.provider.send("hardhat_setBalance", [userAddress2, "0xFFFFFFFFFFFFFFFFFFFFF"]) // create the event - const tmp = await vendor_contract_instance.create_new_event("test", address, 4, 0, [ticket_cost, ticket_cost, ticket_cost, ticket_cost]); + const tmp = await vendor_contract_instance.create_new_event("test", address, 4, 0, ticket_cost); // attach the contract to the user wallet // this means when we call the contracts functions the @@ -499,120 +499,120 @@ describe("VenueMint", function () { // number of events with a random numbers of tickets and have a random number of clients buy // a random number of tickets from a random event and then check that the vendor was payed correctly and // that the user owns the correct tickets - describe("Final Overarching Test", async function () { - it("should work great", async () => { - // gen a ton of random values - let number_vendors = genRandom(2, 20); - let number_clients = number_vendors; - - let vendor_data = Array(); - let vendor_event_nums = Array(); - let total_bought_from_vendor = Array(number_vendors).fill(0); - let vendor_before_balance = Array(number_vendors); - let vendor_after_balance = Array(number_vendors); - - // get the contract - let contract = await loadFixture(deployOne); - - // create the vendors - let vendors = Array(number_vendors); + // describe("Final Overarching Test", async function () { + // it("should work great", async () => { + // // gen a ton of random values + // let number_vendors = genRandom(2, 20); + // let number_clients = number_vendors; + + // let vendor_data = Array(); + // let vendor_event_nums = Array(); + // let total_bought_from_vendor = Array(number_vendors).fill(0); + // let vendor_before_balance = Array(number_vendors); + // let vendor_after_balance = Array(number_vendors); + + // // get the contract + // let contract = await loadFixture(deployOne); + + // // create the vendors + // let vendors = Array(number_vendors); - // setup the vendors - for(let i = 0; i < number_vendors; i++) { - let number_events = genRandom(1,20); - vendor_event_nums.push(number_events); + // // setup the vendors + // for(let i = 0; i < number_vendors; i++) { + // let number_events = genRandom(1,20); + // vendor_event_nums.push(number_events); - let tmp_array = Array(); + // let tmp_array = Array(); - vendors[i] = ethers.Wallet.createRandom().connect(ethers.provider); - let address = await vendors[i].getAddress(); + // vendors[i] = ethers.Wallet.createRandom().connect(ethers.provider); + // let address = await vendors[i].getAddress(); - // give the vendor some money so it can generate tickets - ethers.provider.send("hardhat_setBalance", [address, "0xFFFFFFFFFFFFFFFFFFFFF"]) + // // give the vendor some money so it can generate tickets + // ethers.provider.send("hardhat_setBalance", [address, "0xFFFFFFFFFFFFFFFFFFFFF"]) - let vendor_contract = contract.connect(vendors[i]); + // let vendor_contract = contract.connect(vendors[i]); - for(let j = 0; j < number_events; j++) { - let ticket_cost = genRandom(5,20000); - let number_tickets = genRandom(1,500); - let event_name = `vendor ${i} event ${j}`; + // for(let j = 0; j < number_events; j++) { + // let ticket_cost = genRandom(5,20000); + // let number_tickets = genRandom(1,500); + // let event_name = `vendor ${i} event ${j}`; - await vendor_contract.create_new_event(event_name, `i am vendor ${i}`, number_tickets, 0, Array(number_tickets).fill(ticket_cost)); + // await vendor_contract.create_new_event(event_name, `i am vendor ${i}`, number_tickets, 0, ticket_cost); - tmp_array.push({ticket_cost, number_tickets, event_name}); - } + // tmp_array.push({ticket_cost, number_tickets, event_name}); + // } - vendor_before_balance[i] = await ethers.provider.getBalance(address); + // vendor_before_balance[i] = await ethers.provider.getBalance(address); - vendor_data.push(tmp_array); - } + // vendor_data.push(tmp_array); + // } - let client_data = Array(); - let clients = Array(number_clients); + // let client_data = Array(); + // let clients = Array(number_clients); - let client_vendor_mapping = Array.from({length: number_vendors}, (_, i) => i + 1).sort(() => Math.random() - 0.5).map(num => num-1); + // let client_vendor_mapping = Array.from({length: number_vendors}, (_, i) => i + 1).sort(() => Math.random() - 0.5).map(num => num-1); - // setup the clients and have them buy - for (let i = 0; i < number_clients; i++) { - let num_events = vendor_event_nums[client_vendor_mapping[i]]; - let number_events_to_purchase_from = genRandom(1, num_events); + // // setup the clients and have them buy + // for (let i = 0; i < number_clients; i++) { + // let num_events = vendor_event_nums[client_vendor_mapping[i]]; + // let number_events_to_purchase_from = genRandom(1, num_events); - // long line but basically: - // makes list from 0->num_events then randomly pulls number_events_to_purchase_from events from it - let events_index_array = getRandomElements(Array.from({length: num_events}, (_, i) => i + 1).map(num => num-1), number_events_to_purchase_from); + // // long line but basically: + // // makes list from 0->num_events then randomly pulls number_events_to_purchase_from events from it + // let events_index_array = getRandomElements(Array.from({length: num_events}, (_, i) => i + 1).map(num => num-1), number_events_to_purchase_from); - clients[i] = ethers.Wallet.createRandom().connect(ethers.provider); - let address = await clients[i].getAddress(); + // clients[i] = ethers.Wallet.createRandom().connect(ethers.provider); + // let address = await clients[i].getAddress(); - // give the client some money so it can purchase tickets - ethers.provider.send("hardhat_setBalance", [address, "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"]) + // // give the client some money so it can purchase tickets + // ethers.provider.send("hardhat_setBalance", [address, "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"]) - let client_contract = contract.connect(clients[i]); + // let client_contract = contract.connect(clients[i]); - // gotta figure out our ids now (fuck) - // after a 1.5 hour excursion that works (yay!) - let event_ticket_purchases = Array(); - for (let j = 0; j < number_events_to_purchase_from; j++) { + // // gotta figure out our ids now (fuck) + // // after a 1.5 hour excursion that works (yay!) + // let event_ticket_purchases = Array(); + // for (let j = 0; j < number_events_to_purchase_from; j++) { - let event_data = vendor_data[client_vendor_mapping[i]][events_index_array[j]]; - //console.log(event_data); - let num_tickets_to_purchase = genRandom(1, event_data['number_tickets']); + // let event_data = vendor_data[client_vendor_mapping[i]][events_index_array[j]]; + // //console.log(event_data); + // let num_tickets_to_purchase = genRandom(1, event_data['number_tickets']); - let tickets_to_purchase = [...(await client_contract.get_event_ids(event_data['event_name']))[0].slice(0, num_tickets_to_purchase)]; + // let tickets_to_purchase = [...(await client_contract.get_event_ids(event_data['event_name']))[0].slice(0, num_tickets_to_purchase)]; - let local_cost = num_tickets_to_purchase * event_data['ticket_cost']; - // update total for total money vendor should have - total_bought_from_vendor[client_vendor_mapping[i]] += local_cost; + // let local_cost = num_tickets_to_purchase * event_data['ticket_cost']; + // // update total for total money vendor should have + // total_bought_from_vendor[client_vendor_mapping[i]] += local_cost; - await client_contract.buy_tickets(event_data['event_name'], tickets_to_purchase, {value: ethers.parseEther("1") + BigInt(local_cost)}); + // await client_contract.buy_tickets(event_data['event_name'], tickets_to_purchase, {value: ethers.parseEther("1") + BigInt(local_cost)}); - event_ticket_purchases.push(tickets_to_purchase); - } + // event_ticket_purchases.push(tickets_to_purchase); + // } - client_data.push({number_events_to_purchase_from, event_ticket_purchases}); - } + // client_data.push({number_events_to_purchase_from, event_ticket_purchases}); + // } - // get the vendors balance after the transaction - for (let i = 0; i < number_vendors; i++) { - vendor_after_balance[i] = await ethers.provider.getBalance(await vendors[i].getAddress()); - } + // // get the vendors balance after the transaction + // for (let i = 0; i < number_vendors; i++) { + // vendor_after_balance[i] = await ethers.provider.getBalance(await vendors[i].getAddress()); + // } - // make sure all the vendors got the right amount of money - for (let i = 0; i < number_vendors; i++) { - let diff = vendor_after_balance[i] - vendor_before_balance[i]; + // // make sure all the vendors got the right amount of money + // for (let i = 0; i < number_vendors; i++) { + // let diff = vendor_after_balance[i] - vendor_before_balance[i]; - expect(diff).to.equal(total_bought_from_vendor[i]); - } + // expect(diff).to.equal(total_bought_from_vendor[i]); + // } - // make sure the clients own all the tickets they bought - for (let i = 0; i < clients.length; i++) { - let big_ol_list = client_data[i]['event_ticket_purchases']; + // // make sure the clients own all the tickets they bought + // for (let i = 0; i < clients.length; i++) { + // let big_ol_list = client_data[i]['event_ticket_purchases']; - for (let j = 0; j < big_ol_list.length; j++) { - expect(await contract.balanceOfBatch(Array(big_ol_list[j].length).fill(await clients[i].getAddress()), big_ol_list[j])).to.eql(Array(big_ol_list[j].length).fill(1n)); - } - } - }) - }) + // for (let j = 0; j < big_ol_list.length; j++) { + // expect(await contract.balanceOfBatch(Array(big_ol_list[j].length).fill(await clients[i].getAddress()), big_ol_list[j])).to.eql(Array(big_ol_list[j].length).fill(1n)); + // } + // } + // }) + // }) }) }) From bbb9f773ce5c41df075b1bfda89504e365d12083 Mon Sep 17 00:00:00 2001 From: Christopher Canaday Date: Sun, 27 Apr 2025 17:07:20 -0400 Subject: [PATCH 2/5] added mainnet deploy --- README.md | 4 ++++ hardhat.config.ts | 18 ++++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 953938c..559d2f8 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,10 @@ Generate ABI: `npm run generate_abi_wsl` or `npm run generate_abi` 0x41c3462A19a267D8F5690D5b411c4e46aCf0bbcB +## Mainnet + +0xeB60D2D16F2D48324C84D9ffB26465A88d40659f + ## Steps * npm run rebuild - Will clean and compile all contracts in contracts/ * npx hardhat node (localhost for now) diff --git a/hardhat.config.ts b/hardhat.config.ts index ef1730d..924b977 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -1,15 +1,17 @@ import { HardhatUserConfig } from "hardhat/config"; import "@nomicfoundation/hardhat-toolbox"; import "hardhat-gas-reporter"; -require('dotenv').config(); +require("dotenv").config(); -const poly_api_key = process.env.POLYGONSCAN_API_KEY || "" -const private_key = process.env.PRIVATE_KEY || "0000000000000000000000000000000000000000000000000000000000000000"; -const coinmarketcap_api_key = process.env.COINMARKETCAP_API_KEY || "" +const poly_api_key = process.env.POLYGONSCAN_API_KEY || ""; +const private_key = + process.env.PRIVATE_KEY || + "0000000000000000000000000000000000000000000000000000000000000000"; +const coinmarketcap_api_key = process.env.COINMARKETCAP_API_KEY || ""; const config: HardhatUserConfig = { solidity: "0.8.27", - defaultNetwork: 'hardhat', + defaultNetwork: "hardhat", networks: { hardhat: { blockGasLimit: 1000000000000, // whatever you want here @@ -18,12 +20,16 @@ const config: HardhatUserConfig = { url: `https://rpc-amoy.polygon.technology`, accounts: [private_key], }, + polygon: { + url: `https://polygon-rpc.com/`, + accounts: [private_key], + }, }, etherscan: { apiKey: poly_api_key, }, gasReporter: { - currency: 'USD', + currency: "USD", L1: "polygon", coinmarketcap: coinmarketcap_api_key, L1Etherscan: poly_api_key, From 36b33a111cd2d16edcc7709cce4539ebe33e69d4 Mon Sep 17 00:00:00 2001 From: Christopher Canaday Date: Sun, 27 Apr 2025 17:09:47 -0400 Subject: [PATCH 3/5] update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 559d2f8..c09af51 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Generate ABI: `npm run generate_abi_wsl` or `npm run generate_abi` # Current deployed address -0x41c3462A19a267D8F5690D5b411c4e46aCf0bbcB +0x4B10Ca604B40b782eF00b497357b3dc9478457DF ## Mainnet From 57bfaa7850bef7ac30dfc4ef4dd984453287729c Mon Sep 17 00:00:00 2001 From: Christopher Canaday Date: Sun, 27 Apr 2025 19:02:03 -0400 Subject: [PATCH 4/5] add back ticket_costs mapping --- contracts/VenueMint.sol | 44 ++++++++++++++--------------------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/contracts/VenueMint.sol b/contracts/VenueMint.sol index aae9a09..08d3d5d 100644 --- a/contracts/VenueMint.sol +++ b/contracts/VenueMint.sol @@ -20,7 +20,6 @@ struct Event { string description; Ids ids; address vendor_wallet; - uint256 ticket_cost; } struct EventsIndex { @@ -33,7 +32,7 @@ contract VenueMint is ERC1155Holder, ERC1155 { address private self; // The address of the contract (self) // Mapping nft ids to cost - // mapping(uint256 => uint256) private ticket_costs; + mapping(uint256 => uint256) private ticket_costs; // Mapping ticket id to whether they are allowed to be transferred to another user mapping(uint256 => bool) private id_to_transferable; @@ -66,30 +65,18 @@ contract VenueMint is ERC1155Holder, ERC1155 { //console.log("Contract address is ", self, " and owner address is", owner); } - function get_ticket_cost(uint256 id) view private returns (uint256) { - for (uint256 i = 0; i < events.length; i++) { - Ids memory tmp = events[i].ids; - - if (id >= tmp.min && id <= tmp.max) { - return events[i].ticket_cost; - } - } - - return 0; - } - // 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 cost + uint256[] calldata costs ) public { - // require( - // costs.length == unique_seats + general_admission, - // "Must provide the same number of costs as general admission and unique seats." - // ); + 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, @@ -108,11 +95,11 @@ contract VenueMint is ERC1155Holder, ERC1155 { for (; i < last_id + ids.length; ++i) { ids[i - last_id] = i; amounts[i - last_id] = 1; - // if (i < unique_seats) { - // ticket_costs[i] = costs[i - last_id]; - // } else { - // ticket_costs[i] = costs[costs.length - 1]; - // } + if (i < unique_seats) { + ticket_costs[i] = costs[i - last_id]; + } else { + ticket_costs[i] = costs[costs.length - 1]; + } } // keep track of the NFT ids for the event @@ -131,8 +118,7 @@ contract VenueMint is ERC1155Holder, ERC1155 { description: description, count: general_admission + unique_seats, ids: tmp, - vendor_wallet: payable(msg.sender), - ticket_cost: cost + vendor_wallet: payable(msg.sender) }) ); @@ -220,7 +206,7 @@ contract VenueMint is ERC1155Holder, ERC1155 { ) public view returns (uint256) { uint256 total_cost = 0; for (uint256 i = 0; i < ids.length; ++i) { - total_cost += get_ticket_cost(ids[i]); + total_cost += ticket_costs[ids[i]]; } return total_cost; } @@ -245,7 +231,7 @@ contract VenueMint is ERC1155Holder, ERC1155 { "One of these tickets has already been sold." ); - total_cost += get_ticket_cost(ids[i]); + total_cost += ticket_costs[ids[i]]; } // Check if they are able to buy those tickets and that they have enough money @@ -336,7 +322,7 @@ contract VenueMint is ERC1155Holder, ERC1155 { "Requested seller does not own the ticket." ); - uint256 cost = get_ticket_cost(ticketid); + uint256 cost = ticket_costs[ticketid]; require( msg.value >= cost, From 893786c9d6237960c847b407609a980a8fd08dac Mon Sep 17 00:00:00 2001 From: Christopher Canaday Date: Sun, 27 Apr 2025 21:31:08 -0400 Subject: [PATCH 5/5] finished --- README.md | 2 +- package.json | 4 +- test/VenueMint.ts | 1483 +++++++++++++++++++++++++++------------------ 3 files changed, 885 insertions(+), 604 deletions(-) diff --git a/README.md b/README.md index c09af51..2e07bc5 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Generate ABI: `npm run generate_abi_wsl` or `npm run generate_abi` # Current deployed address -0x4B10Ca604B40b782eF00b497357b3dc9478457DF +0x8BE301eD017D23977F98b48CD9D18EaB91C0ae26 ## Mainnet diff --git a/package.json b/package.json index bc49244..aa58953 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,8 @@ "deploy_mint": "npx hardhat ignition deploy ./ignition/modules/VenueMint.ts --network localhost", "deploy": "rm -r ./ignition/deployments ; npx hardhat ignition deploy ./ignition/modules/VenueMint.ts --network polygon_amoy", "local_console": "npx hardhat console --network localhost", - "generate_abi": "solc-windows.exe --base-path . --include-path node_modules\\ contracts\\VenueMint.sol --abi -o abis --overwrite", - "generate_abi_wsl": "solc --base-path . --include-path ./node_modules/ ./contracts/VenueMint.sol --abi -o abis --overwrite" + "generate_abi": "./solc-windows.exe --base-path . --include-path node_modules\\ contracts\\VenueMint.sol --abi -o abis --overwrite", + "generate_abi_wsl": "./solc-windows.exe --base-path . --include-path ./node_modules/ ./contracts/VenueMint.sol --abi -o abis --overwrite" }, "author": "", "license": "ISC", diff --git a/test/VenueMint.ts b/test/VenueMint.ts index 77bf383..66cb7c9 100644 --- a/test/VenueMint.ts +++ b/test/VenueMint.ts @@ -7,612 +7,893 @@ import { utils } from "../typechain-types/@openzeppelin/contracts"; // overall testing framework describe("VenueMint", function () { - - // function for deploying - // when called from loadFixture it will only actually be called once - // then stored for later calls - async function deployOne() { - const VenueMint = await hre.ethers.getContractFactory("VenueMint"); - const contract = await VenueMint.deploy(); - return contract; - } - - function genRandom(min: number, max: number) { - const minCeiled = Math.ceil(min); - const maxFloored = Math.floor(max); - - // return the random value - return Math.floor(Math.random() * (maxFloored - minCeiled) + minCeiled); + // function for deploying + // when called from loadFixture it will only actually be called once + // then stored for later calls + async function deployOne() { + const VenueMint = await hre.ethers.getContractFactory("VenueMint"); + const contract = await VenueMint.deploy(); + return contract; + } + + function genRandom(min: number, max: number) { + const minCeiled = Math.ceil(min); + const maxFloored = Math.floor(max); + + // return the random value + return Math.floor(Math.random() * (maxFloored - minCeiled) + minCeiled); + } + + // generously generated by google ai overview + function getRandomElements(list: T[], numElements: number): T[] { + if (numElements > list.length) { + throw new Error( + "Number of elements to select cannot be greater than the list length." + ); } - // generously generated by google ai overview - function getRandomElements(list: T[], numElements: number): T[] { - if (numElements > list.length) { - throw new Error("Number of elements to select cannot be greater than the list length."); + const shuffled = [...list].sort(() => 0.5 - Math.random()); + return shuffled.slice(0, numElements); + } + + // check core functionality of the contract + describe("Core Functionality", function () { + // check that the contract properly deploys + it("should deploy", async () => { + const contract = await loadFixture(deployOne); + expect(contract).to.be; + }); + + // basic check to make sure the create_new_event function is creating NFTs + // this checks that the contract owns the nft after creation + it("can create an nft", async () => { + const contract = await loadFixture(deployOne); + await contract.create_new_event("test", "0xblahblahblah", 1, 0, [5]); + expect( + await contract.balanceOfBatch([await contract.getAddress()], [0]) + ).to.eql([1n]); + }); + + // checks that purchasing a single ticket works with a separate user and vendor wallet + it("can purchase single ticket", async () => { + const init_contract = await loadFixture(deployOne); + + // vendor wallet and address + const wallet = ethers.Wallet.createRandom().connect(ethers.provider); + const address = await wallet.getAddress(); + + // add a ton of fake money to the vendor wallet + const vendor_contract_instance = init_contract.connect(wallet); + + ethers.provider.send("hardhat_setBalance", [ + address, + "0xFFFFFFFFFFFFFFFFFFFFF", + ]); + + // user wallet and address + const userWallet = ethers.Wallet.createRandom().connect(ethers.provider); + const userAddress = await userWallet.getAddress(); + + // add a ton of fake money to the user wallet + ethers.provider.send("hardhat_setBalance", [ + userAddress, + "0xFFFFFFFFFFFFFFFFFFFFF", + ]); + + // create the event + const tmp = await vendor_contract_instance.create_new_event( + "test", + address, + 1, + 0, + [5000] + ); + + // attach the contract to the user wallet + // this means when we call the contracts functions the + // sender (signer) will be the user wallet + const user_contract_instance = + vendor_contract_instance.connect(userWallet); + + // buy the tickets (way too much money give here) + const resp = await user_contract_instance.buy_tickets("test", [0], { + value: ethers.parseEther("1"), + }); + + // check that the user wallet now owns the NFT + expect( + await user_contract_instance.balanceOfBatch([userAddress], [0]) + ).to.eql([1n]); + }); + + // tests if 2 NFTs can be created + it("can create multiple nfts", async () => { + const contract = await loadFixture(deployOne); + const contract_address = await contract.getAddress(); + await contract.create_new_event("test", contract_address, 2, 0, [5, 5]); + expect( + await contract.balanceOfBatch( + [contract_address, contract_address], + [0, 1] + ) + ).to.eql([1n, 1n]); + }); + + // tests if the contract properly generates NFTs after generating other ones + // does this for a relatively small number of NFTs + it("can create 100-1000 NFTs", async () => { + const contract = await loadFixture(deployOne); + const contract_address = await contract.getAddress(); + let max = 10; + let base = 100; + let total_so_far = 0; + + for (let i = 1; i <= max; i++) { + // create the events + await contract.create_new_event( + `test ${i * base}`, + contract_address, + i * base, + 0, + Array(i * base).fill(5) + ); + + // check that the contract owns all the events + expect( + await contract.balanceOfBatch( + Array(i * base).fill(contract_address), + Array.from({ length: i * base }, (_, i) => i + total_so_far) + ) + ).to.eql(Array(i * base).fill(1n)); + total_so_far += i * max; + } + }); + + it("can get the ids of an event", async () => { + const contract = await loadFixture(deployOne); + + const tmp = await contract.create_new_event( + "test", + "0xblahblah", + 5, + 0, + [5, 5, 5, 5, 5] + ); + + // check that it returns properly for a valid and non valid event + expect((await contract.get_event_ids("test"))[0]).to.eql( + Array(0n, 1n, 2n, 3n, 4n) + ); + expect(contract.get_event_ids("")).to.rejectedWith(Error); + }); + + it("will update the available ids for an event", async () => { + const contract = await loadFixture(deployOne); + const user = ethers.Wallet.createRandom().connect(ethers.provider); + const user_address = await user.getAddress(); + ethers.provider.send("hardhat_setBalance", [ + user_address, + "0xFFFFFFFFFFFFFFFFFFFFF", + ]); + + await contract.create_new_event( + "test", + "0xblahblah", + 5, + 0, + [5, 5, 5, 5, 5] + ); + + const user_contract_instance = contract.connect(user); + await user_contract_instance.buy_tickets("test", [0], { + value: ethers.parseEther("1"), + }); + + expect((await contract.get_event_ids("test"))[0]).to.eql( + Array(1n, 2n, 3n, 4n) + ); + }); + + it("will validate the description", async () => { + const contract = await loadFixture(deployOne); + + const tmp = await contract.is_description_available("test"); + + expect(tmp).to.equal(true); + + await contract.create_new_event("test", "tme", 1, 0, [1]); + + expect(await contract.is_description_available("test")).to.equal(false); + }); + + describe("User to User Ticket Transfer", function () { + it("properly transfers tickets from user to user", async () => { + const init_contract = await loadFixture(deployOne); + + // make wallets + const nftholderwallet = ethers.Wallet.createRandom().connect( + ethers.provider + ); + const nftholderaddress = await nftholderwallet.getAddress(); + const nftpurchaserwallet = ethers.Wallet.createRandom().connect( + ethers.provider + ); + const nftpurchaseraddress = await nftpurchaserwallet.getAddress(); + + // give both money + ethers.provider.send("hardhat_setBalance", [ + nftholderaddress, + "0xFFFFFFFFFFFFFFFFFFFFF", + ]); + ethers.provider.send("hardhat_setBalance", [ + nftpurchaseraddress, + "0xFFFFFFFFFFFFFFFFFFFFF", + ]); + + // make the holder instance and create the event + const holder_instance = init_contract.connect(nftholderwallet); + const tmp = await holder_instance.create_new_event( + "test", + "cool beans", + 1, + 0, + [2000] + ); + + // 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(); + 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 + var disallow_ran = false; + const holderfilter = + init_contract.filters.User_To_User_Transfer_Concluded( + nftholderaddress, + nftpurchaseraddress + ); + + // this is here purely for example (it is not necessary for our tests) + // setup a listener that removes the contracts ability to manage the holders tokens + holder_instance.on(holderfilter, async (response) => { + await holder_instance.disallow_user_to_user_ticket_transfer(); + disallow_ran = true; + }); + + // create the purchaser instance + const purchaser_instance = holder_instance.connect(nftpurchaserwallet); + + const holder_balance_before = await ethers.provider.getBalance( + nftholderaddress + ); + + // make sure that the ticket buying function emits the correct events + // make sure that the ticket was properly transfered from the two wallets + expect( + await purchaser_instance.buy_ticket_from_user(nftholderaddress, 0, { + value: ethers.parseEther("1"), + }) + ) + .to.emit(purchaser_instance, "User_To_User_Transfer_Concluded") + .withArgs(nftholderaddress, nftpurchaseraddress); + expect( + await purchaser_instance.balanceOf(nftpurchaseraddress, 0) + ).to.equal(1n); + + // make sure the seller got the correct amount of money + const holder_balance_after = await ethers.provider.getBalance( + nftholderaddress + ); + expect(holder_balance_after - holder_balance_before).to.equal(2000); + + // wait 5 seconds this is required for this to work right + // explanation here: https://stackoverflow.com/questions/68432609/contract-event-listener-is-not-firing-when-running-hardhat-tests-with-ethers-js + await new Promise((res) => setTimeout(() => res(null), 5000)); + + // make sure the listener caught the event + expect(disallow_ran).to.equal(true); + }); + }); + + describe("Vendor Payment Functionality", function () { + // checks that the vendor recieves the funds from one transaction + it("properly pays the vendor", async () => { + const init_contract = await loadFixture(deployOne); + + // randomly calculate cost of the ticket + let ticket_cost = genRandom(5, 100000); + + // vendor wallet and address + const wallet = ethers.Wallet.createRandom().connect(ethers.provider); + const address = await wallet.getAddress(); + + // add a ton of fake money to the vendor wallet + const vendor_contract_instance = init_contract.connect(wallet); + + ethers.provider.send("hardhat_setBalance", [ + address, + "0xFFFFFFFFFFFFFFFFFFFFF", + ]); + + // user wallet and address + const userWallet = ethers.Wallet.createRandom().connect( + ethers.provider + ); + const userAddress = await userWallet.getAddress(); + + // add a ton of fake money to the user wallet + ethers.provider.send("hardhat_setBalance", [ + userAddress, + "0xFFFFFFFFFFFFFFFFFFFFF", + ]); + + // create the event + const tmp = await vendor_contract_instance.create_new_event( + "test", + address, + 1, + 0, + [ticket_cost] + ); + + // attach the contract to the user wallet + // this means when we call the contracts functions the + // sender (signer) will be the user wallet + const user_contract_instance = + vendor_contract_instance.connect(userWallet); + + const vendor_balance_before = await ethers.provider.getBalance(address); + + // buy the tickets (way too much money give here) + const resp = await user_contract_instance.buy_tickets("test", [0], { + value: ethers.parseEther("1"), + }); + + const vendor_balance_after = await ethers.provider.getBalance(address); + + // check that the vendor wallet gained the correct amount of money + expect(vendor_balance_after - vendor_balance_before).is.equal( + ticket_cost + ); + }); + + // checks that the vendor is paid properly when batch buying tickets + it("properly pays the vendor when batch buying multiple tickets", async () => { + const init_contract = await loadFixture(deployOne); + + // randomly calculate cost of the ticket + let ticket_cost = genRandom(5, 100000); + + // vendor wallet and address + const wallet = ethers.Wallet.createRandom().connect(ethers.provider); + const address = await wallet.getAddress(); + + // add a ton of fake money to the vendor wallet + const vendor_contract_instance = init_contract.connect(wallet); + + ethers.provider.send("hardhat_setBalance", [ + address, + "0xFFFFFFFFFFFFFFFFFFFFF", + ]); + + // user wallet and address + const userWallet = ethers.Wallet.createRandom().connect( + ethers.provider + ); + const userAddress = await userWallet.getAddress(); + + // add a ton of fake money to the user wallet + ethers.provider.send("hardhat_setBalance", [ + userAddress, + "0xFFFFFFFFFFFFFFFFFFFFF", + ]); + + // create the event + const tmp = await vendor_contract_instance.create_new_event( + "test", + address, + 2, + 0, + [ticket_cost, ticket_cost] + ); + + // attach the contract to the user wallet + // this means when we call the contracts functions the + // sender (signer) will be the user wallet + const user_contract_instance = + vendor_contract_instance.connect(userWallet); + + const vendor_balance_before = await ethers.provider.getBalance(address); + + // buy the tickets (way too much money give here) + const resp = await user_contract_instance.buy_tickets("test", [0, 1], { + value: ethers.parseEther("1"), + }); + + const vendor_balance_after = await ethers.provider.getBalance(address); + + // check that the vendor wallet gained the correct amount of money + expect(vendor_balance_after - vendor_balance_before).is.equal( + ticket_cost * 2 + ); + }); + + // checks that the vendor is paid properly when buying multiple tickets separately + it("properly pays the vendor when buying multiple tickets in individual transactions", async () => { + const init_contract = await loadFixture(deployOne); + + // randomly calculate cost of the ticket + let ticket_cost = genRandom(5, 100000); + + // vendor wallet and address + const wallet = ethers.Wallet.createRandom().connect(ethers.provider); + const address = await wallet.getAddress(); + + // add a ton of fake money to the vendor wallet + const vendor_contract_instance = init_contract.connect(wallet); + + ethers.provider.send("hardhat_setBalance", [ + address, + "0xFFFFFFFFFFFFFFFFFFFFF", + ]); + + // user wallet and address + const userWallet = ethers.Wallet.createRandom().connect( + ethers.provider + ); + const userAddress = await userWallet.getAddress(); + + // add a ton of fake money to the user wallet + ethers.provider.send("hardhat_setBalance", [ + userAddress, + "0xFFFFFFFFFFFFFFFFFFFFF", + ]); + + // create the event + const tmp = await vendor_contract_instance.create_new_event( + "test", + address, + 2, + 0, + [ticket_cost, ticket_cost] + ); + + // attach the contract to the user wallet + // this means when we call the contracts functions the + // sender (signer) will be the user wallet + const user_contract_instance = + vendor_contract_instance.connect(userWallet); + + const vendor_balance_before = await ethers.provider.getBalance(address); + + // buy the tickets (way too much money give here) + const resp = await user_contract_instance.buy_tickets("test", [0], { + value: ethers.parseEther("1"), + }); + const resp2 = await user_contract_instance.buy_tickets("test", [1], { + value: ethers.parseEther("1"), + }); + + const vendor_balance_after = await ethers.provider.getBalance(address); + + // check that the vendor wallet gained the correct amount of money + expect(vendor_balance_after - vendor_balance_before).is.equal( + ticket_cost * 2 + ); + }); + + // checks that the vendor is paid properly when mutliple users buy a ticket + it("properly pays the vendor when multiple users buy a ticket", async () => { + const init_contract = await loadFixture(deployOne); + + // randomly calculate cost of the ticket + let ticket_cost = genRandom(5, 100000); + + // vendor wallet and address + const wallet = ethers.Wallet.createRandom().connect(ethers.provider); + const address = await wallet.getAddress(); + + // add a ton of fake money to the vendor wallet + const vendor_contract_instance = init_contract.connect(wallet); + + ethers.provider.send("hardhat_setBalance", [ + address, + "0xFFFFFFFFFFFFFFFFFFFFF", + ]); + + // user wallet and address + const userWallet = ethers.Wallet.createRandom().connect( + ethers.provider + ); + const userAddress = await userWallet.getAddress(); + + // add a ton of fake money to the user wallet + ethers.provider.send("hardhat_setBalance", [ + userAddress, + "0xFFFFFFFFFFFFFFFFFFFFF", + ]); + + // second user wallet and address + const userWallet2 = ethers.Wallet.createRandom().connect( + ethers.provider + ); + const userAddress2 = await userWallet2.getAddress(); + + // add a ton of fake money to the second user wallet + ethers.provider.send("hardhat_setBalance", [ + userAddress2, + "0xFFFFFFFFFFFFFFFFFFFFF", + ]); + + // create the event + const tmp = await vendor_contract_instance.create_new_event( + "test", + address, + 2, + 0, + [ticket_cost, ticket_cost] + ); + + // attach the contract to the user wallet + // this means when we call the contracts functions the + // sender (signer) will be the user wallet + const user_contract_instance = + vendor_contract_instance.connect(userWallet); + + const vendor_balance_before = await ethers.provider.getBalance(address); + + // buy the tickets (way too much money give here) + const resp = await user_contract_instance.buy_tickets("test", [0], { + value: ethers.parseEther("1"), + }); + + const user2_contract_instance = + user_contract_instance.connect(userWallet2); + + const resp2 = await user2_contract_instance.buy_tickets("test", [1], { + value: ethers.parseEther("1"), + }); + + const vendor_balance_after = await ethers.provider.getBalance(address); + + // check that the vendor wallet gained the correct amount of money + expect(vendor_balance_after - vendor_balance_before).is.equal( + ticket_cost * 2 + ); + }); + + // checks that the vendor is paid properly when mutliple users buy multiple tickets + it("properly pays the vendor when multiple users buy multiple tickets", async () => { + const init_contract = await loadFixture(deployOne); + + // randomly calculate cost of the ticket + let ticket_cost = genRandom(5, 100000); + + // vendor wallet and address + const wallet = ethers.Wallet.createRandom().connect(ethers.provider); + const address = await wallet.getAddress(); + + // add a ton of fake money to the vendor wallet + const vendor_contract_instance = init_contract.connect(wallet); + + ethers.provider.send("hardhat_setBalance", [ + address, + "0xFFFFFFFFFFFFFFFFFFFFF", + ]); + + // user wallet and address + const userWallet = ethers.Wallet.createRandom().connect( + ethers.provider + ); + const userAddress = await userWallet.getAddress(); + + // add a ton of fake money to the user wallet + ethers.provider.send("hardhat_setBalance", [ + userAddress, + "0xFFFFFFFFFFFFFFFFFFFFF", + ]); + + // second user wallet and address + const userWallet2 = ethers.Wallet.createRandom().connect( + ethers.provider + ); + const userAddress2 = await userWallet2.getAddress(); + + // add a ton of fake money to the second user wallet + ethers.provider.send("hardhat_setBalance", [ + userAddress2, + "0xFFFFFFFFFFFFFFFFFFFFF", + ]); + + // create the event + const tmp = await vendor_contract_instance.create_new_event( + "test", + address, + 4, + 0, + [ticket_cost, ticket_cost, ticket_cost, ticket_cost] + ); + + // attach the contract to the user wallet + // this means when we call the contracts functions the + // sender (signer) will be the user wallet + const user_contract_instance = + vendor_contract_instance.connect(userWallet); + + const vendor_balance_before = await ethers.provider.getBalance(address); + + // buy the tickets (way too much money give here) + const resp = await user_contract_instance.buy_tickets("test", [0, 1], { + value: ethers.parseEther("1"), + }); + + const user2_contract_instance = + user_contract_instance.connect(userWallet2); + + const resp2 = await user2_contract_instance.buy_tickets( + "test", + [2, 3], + { value: ethers.parseEther("1") } + ); + + const vendor_balance_after = await ethers.provider.getBalance(address); + + // check that the vendor wallet gained the correct amount of money + expect(vendor_balance_after - vendor_balance_before).is.equal( + ticket_cost * 4 + ); + }); + + it("doesn't try to double sell a ticket in a batch event", async () => { + const init_contract = await loadFixture(deployOne); + + // randomly calculate cost of the ticket + let ticket_cost = genRandom(5, 100000); + + // vendor wallet and address + const wallet = ethers.Wallet.createRandom().connect(ethers.provider); + const address = await wallet.getAddress(); + + // add a ton of fake money to the vendor wallet + const vendor_contract_instance = init_contract.connect(wallet); + + ethers.provider.send("hardhat_setBalance", [ + address, + "0xFFFFFFFFFFFFFFFFFFFFF", + ]); + + // user wallet and address + const userWallet = ethers.Wallet.createRandom().connect( + ethers.provider + ); + const userAddress = await userWallet.getAddress(); + + // add a ton of fake money to the user wallet + ethers.provider.send("hardhat_setBalance", [ + userAddress, + "0xFFFFFFFFFFFFFFFFFFFFF", + ]); + + // second user wallet and address + const userWallet2 = ethers.Wallet.createRandom().connect( + ethers.provider + ); + const userAddress2 = await userWallet2.getAddress(); + + // add a ton of fake money to the second user wallet + ethers.provider.send("hardhat_setBalance", [ + userAddress2, + "0xFFFFFFFFFFFFFFFFFFFFF", + ]); + + // create the event + const tmp = await vendor_contract_instance.create_new_event( + "test", + address, + 4, + 0, + [ticket_cost, ticket_cost, ticket_cost, ticket_cost] + ); + + // attach the contract to the user wallet + // this means when we call the contracts functions the + // sender (signer) will be the user wallet + const user_contract_instance = + vendor_contract_instance.connect(userWallet); + + const vendor_balance_before = await ethers.provider.getBalance(address); + + // buy the tickets (way too much money give here) + const resp = await user_contract_instance.buy_tickets("test", [0, 1], { + value: ethers.parseEther("1"), + }); + + const user2_contract_instance = + user_contract_instance.connect(userWallet2); + + expect( + user2_contract_instance.buy_tickets("test", [1, 2], { + value: ethers.parseEther("1"), + }) + ).to.rejectedWith(Error); + + const vendor_balance_after = await ethers.provider.getBalance(address); + + // check that the vendor wallet gained the correct amount of money + expect(vendor_balance_after - vendor_balance_before).is.equal( + ticket_cost * 2 + ); + }); + }); + + // so the goal here is to have random number of vendors generate a random + // number of events with a random numbers of tickets and have a random number of clients buy + // a random number of tickets from a random event and then check that the vendor was payed correctly and + // that the user owns the correct tickets + describe("Final Overarching Test", async function () { + it("should work great", async () => { + // gen a ton of random values + let number_vendors = genRandom(2, 20); + let number_clients = number_vendors; + + let vendor_data = Array(); + let vendor_event_nums = Array(); + let total_bought_from_vendor = Array(number_vendors).fill(0); + let vendor_before_balance = Array(number_vendors); + let vendor_after_balance = Array(number_vendors); + + // get the contract + let contract = await loadFixture(deployOne); + + // create the vendors + let vendors = Array(number_vendors); + + // setup the vendors + for (let i = 0; i < number_vendors; i++) { + let number_events = genRandom(1, 20); + vendor_event_nums.push(number_events); + + let tmp_array = Array(); + + vendors[i] = ethers.Wallet.createRandom().connect(ethers.provider); + let address = await vendors[i].getAddress(); + + // give the vendor some money so it can generate tickets + ethers.provider.send("hardhat_setBalance", [ + address, + "0xFFFFFFFFFFFFFFFFFFFFF", + ]); + + let vendor_contract = contract.connect(vendors[i]); + + for (let j = 0; j < number_events; j++) { + let ticket_cost = genRandom(5, 20000); + let number_tickets = genRandom(1, 500); + let event_name = `vendor ${i} event ${j}`; + + await vendor_contract.create_new_event( + event_name, + `i am vendor ${i}`, + number_tickets, + 0, + Array(number_tickets).fill(ticket_cost) + ); + + tmp_array.push({ ticket_cost, number_tickets, event_name }); + } + + vendor_before_balance[i] = await ethers.provider.getBalance(address); + + vendor_data.push(tmp_array); } - - const shuffled = [...list].sort(() => 0.5 - Math.random()); - return shuffled.slice(0, numElements); - } - - // check core functionality of the contract - describe("Core Functionality", function () { - // check that the contract properly deploys - it("should deploy", async () => { - const contract = await loadFixture(deployOne); - expect(contract).to.be; - }) - - // basic check to make sure the create_new_event function is creating NFTs - // this checks that the contract owns the nft after creation - it("can create an nft", async () => { - const contract = await loadFixture(deployOne); - await contract.create_new_event("test", "0xblahblahblah", 1, 0, 5) - expect(await contract.balanceOfBatch([await contract.getAddress()], [0])).to.eql([1n]) - }) - - // checks that purchasing a single ticket works with a separate user and vendor wallet - it("can purchase single ticket", async () => { - const init_contract = await loadFixture(deployOne); - - // vendor wallet and address - const wallet = ethers.Wallet.createRandom().connect(ethers.provider); - const address = await wallet.getAddress(); - - // add a ton of fake money to the vendor wallet - const vendor_contract_instance = init_contract.connect(wallet); - - ethers.provider.send("hardhat_setBalance", [address, "0xFFFFFFFFFFFFFFFFFFFFF"]) - - // user wallet and address - const userWallet = ethers.Wallet.createRandom().connect(ethers.provider); - const userAddress = await userWallet.getAddress(); - - // add a ton of fake money to the user wallet - ethers.provider.send("hardhat_setBalance", [userAddress, "0xFFFFFFFFFFFFFFFFFFFFF"]) - - // create the event - const tmp = await vendor_contract_instance.create_new_event("test", address, 1, 0, 5000) - - // attach the contract to the user wallet - // this means when we call the contracts functions the - // sender (signer) will be the user wallet - const user_contract_instance = vendor_contract_instance.connect(userWallet) - - // buy the tickets (way too much money give here) - const resp = await user_contract_instance.buy_tickets("test", [0], {value: ethers.parseEther("1")}); - - // check that the user wallet now owns the NFT - expect(await user_contract_instance.balanceOfBatch([userAddress], [0])).to.eql([1n]); - }) - - // tests if 2 NFTs can be created - it("can create multiple nfts", async () => { - const contract = await loadFixture(deployOne); - const contract_address = await contract.getAddress(); - await contract.create_new_event("test", contract_address, 2, 0, 5); - expect(await contract.balanceOfBatch([contract_address, contract_address], [0,1])).to.eql([1n,1n]) - }) - - // tests if the contract properly generates NFTs after generating other ones - // does this for a relatively small number of NFTs - it("can create 100-1000 NFTs", async () => { - const contract = await loadFixture(deployOne); - const contract_address = await contract.getAddress(); - let max = 10; - let base = 100; - let total_so_far = 0; - - for(let i = 1; i <= max; i++) { - // create the events - await contract.create_new_event(`test ${i*base}`, contract_address, i*base, 0, 5); - - // check that the contract owns all the events - expect(await contract.balanceOfBatch(Array(i*base).fill(contract_address), Array.from({length: i*base}, (_, i) => i + total_so_far))).to.eql(Array(i*base).fill(1n)); - total_so_far += i*max; - } - }) - - it("can get the ids of an event", async () => { - const contract = await loadFixture(deployOne); - - const tmp = await contract.create_new_event("test", "0xblahblah", 5, 0, 5); - - // check that it returns properly for a valid and non valid event - expect((await contract.get_event_ids("test"))[0]).to.eql(Array(0n,1n,2n,3n,4n)); - expect(contract.get_event_ids("")).to.rejectedWith(Error); - }) - - it("will update the available ids for an event", async () => { - const contract = await loadFixture(deployOne); - const user = ethers.Wallet.createRandom().connect(ethers.provider); - const user_address = await user.getAddress(); - ethers.provider.send("hardhat_setBalance", [user_address, "0xFFFFFFFFFFFFFFFFFFFFF"]) - - await contract.create_new_event("test", "0xblahblah", 5, 0, 5); - - const user_contract_instance = contract.connect(user); - await user_contract_instance.buy_tickets("test", [0], {value: ethers.parseEther("1")}); - - expect((await contract.get_event_ids("test"))[0]).to.eql(Array(1n,2n,3n,4n)) - }) - - it("will validate the description", async () => { - const contract = await loadFixture(deployOne); - - const tmp = await contract.is_description_available("test"); - - expect(tmp).to.equal(true); - - await contract.create_new_event("test", "tme", 1, 0, 1); - - expect(await contract.is_description_available("test")).to.equal(false); - }) - - describe("User to User Ticket Transfer", function () { - it("properly transfers tickets from user to user", async () => { - const init_contract = await loadFixture(deployOne); - - // make wallets - const nftholderwallet = ethers.Wallet.createRandom().connect(ethers.provider); - const nftholderaddress = await nftholderwallet.getAddress(); - const nftpurchaserwallet = ethers.Wallet.createRandom().connect(ethers.provider); - const nftpurchaseraddress = await nftpurchaserwallet.getAddress(); - - // give both money - ethers.provider.send("hardhat_setBalance", [nftholderaddress, "0xFFFFFFFFFFFFFFFFFFFFF"]); - ethers.provider.send("hardhat_setBalance", [nftpurchaseraddress, "0xFFFFFFFFFFFFFFFFFFFFF"]); - - // make the holder instance and create the event - const holder_instance = init_contract.connect(nftholderwallet); - const tmp = await holder_instance.create_new_event("test", "cool beans", 1, 0, 2000); - - // 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(); - 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 - var disallow_ran = false; - const holderfilter = init_contract.filters.User_To_User_Transfer_Concluded(nftholderaddress, nftpurchaseraddress); - - // this is here purely for example (it is not necessary for our tests) - // setup a listener that removes the contracts ability to manage the holders tokens - holder_instance.on(holderfilter, async (response) => { - await holder_instance.disallow_user_to_user_ticket_transfer(); - disallow_ran = true; - }); - - // create the purchaser instance - const purchaser_instance = holder_instance.connect(nftpurchaserwallet); - - const holder_balance_before = await ethers.provider.getBalance(nftholderaddress); - - // make sure that the ticket buying function emits the correct events - // make sure that the ticket was properly transfered from the two wallets - expect(await purchaser_instance.buy_ticket_from_user(nftholderaddress,0, {value: ethers.parseEther("1")})).to.emit(purchaser_instance, "User_To_User_Transfer_Concluded").withArgs(nftholderaddress, nftpurchaseraddress); - expect(await purchaser_instance.balanceOf(nftpurchaseraddress, 0)).to.equal(1n); - - // make sure the seller got the correct amount of money - const holder_balance_after = await ethers.provider.getBalance(nftholderaddress); - expect(holder_balance_after - holder_balance_before).to.equal(2000); - - // wait 5 seconds this is required for this to work right - // explanation here: https://stackoverflow.com/questions/68432609/contract-event-listener-is-not-firing-when-running-hardhat-tests-with-ethers-js - await new Promise(res => setTimeout(() => res(null), 5000)); - - // make sure the listener caught the event - expect(disallow_ran).to.equal(true); - }) - }) - - describe("Vendor Payment Functionality", function () { - - // checks that the vendor recieves the funds from one transaction - it("properly pays the vendor", async () => { - const init_contract = await loadFixture(deployOne); - - // randomly calculate cost of the ticket - let ticket_cost = genRandom(5, 100000); - - // vendor wallet and address - const wallet = ethers.Wallet.createRandom().connect(ethers.provider); - const address = await wallet.getAddress(); - - // add a ton of fake money to the vendor wallet - const vendor_contract_instance = init_contract.connect(wallet); - - ethers.provider.send("hardhat_setBalance", [address, "0xFFFFFFFFFFFFFFFFFFFFF"]) - - // user wallet and address - const userWallet = ethers.Wallet.createRandom().connect(ethers.provider); - const userAddress = await userWallet.getAddress(); - - // add a ton of fake money to the user wallet - ethers.provider.send("hardhat_setBalance", [userAddress, "0xFFFFFFFFFFFFFFFFFFFFF"]) - - // create the event - const tmp = await vendor_contract_instance.create_new_event("test", address, 1, 0, ticket_cost); - - // attach the contract to the user wallet - // this means when we call the contracts functions the - // sender (signer) will be the user wallet - const user_contract_instance = vendor_contract_instance.connect(userWallet) - - const vendor_balance_before = await ethers.provider.getBalance(address); - - // buy the tickets (way too much money give here) - const resp = await user_contract_instance.buy_tickets("test", [0], {value: ethers.parseEther("1")}); - - const vendor_balance_after = await ethers.provider.getBalance(address); - - // check that the vendor wallet gained the correct amount of money - expect(vendor_balance_after - vendor_balance_before).is.equal(ticket_cost); - }) - - // checks that the vendor is paid properly when batch buying tickets - it("properly pays the vendor when batch buying multiple tickets", async () => { - const init_contract = await loadFixture(deployOne); - - // randomly calculate cost of the ticket - let ticket_cost = genRandom(5, 100000); - - // vendor wallet and address - const wallet = ethers.Wallet.createRandom().connect(ethers.provider); - const address = await wallet.getAddress(); - - // add a ton of fake money to the vendor wallet - const vendor_contract_instance = init_contract.connect(wallet); - - ethers.provider.send("hardhat_setBalance", [address, "0xFFFFFFFFFFFFFFFFFFFFF"]) - - // user wallet and address - const userWallet = ethers.Wallet.createRandom().connect(ethers.provider); - const userAddress = await userWallet.getAddress(); - - // add a ton of fake money to the user wallet - ethers.provider.send("hardhat_setBalance", [userAddress, "0xFFFFFFFFFFFFFFFFFFFFF"]) - - // create the event - const tmp = await vendor_contract_instance.create_new_event("test", address, 2, 0, ticket_cost); - - // attach the contract to the user wallet - // this means when we call the contracts functions the - // sender (signer) will be the user wallet - const user_contract_instance = vendor_contract_instance.connect(userWallet) - - const vendor_balance_before = await ethers.provider.getBalance(address); - - // buy the tickets (way too much money give here) - const resp = await user_contract_instance.buy_tickets("test", [0,1], {value: ethers.parseEther("1")}); - - const vendor_balance_after = await ethers.provider.getBalance(address); - - // check that the vendor wallet gained the correct amount of money - expect(vendor_balance_after - vendor_balance_before).is.equal(ticket_cost*2); - }) - - // checks that the vendor is paid properly when buying multiple tickets separately - it("properly pays the vendor when buying multiple tickets in individual transactions", async () => { - const init_contract = await loadFixture(deployOne); - - // randomly calculate cost of the ticket - let ticket_cost = genRandom(5, 100000); - - // vendor wallet and address - const wallet = ethers.Wallet.createRandom().connect(ethers.provider); - const address = await wallet.getAddress(); - - // add a ton of fake money to the vendor wallet - const vendor_contract_instance = init_contract.connect(wallet); - - ethers.provider.send("hardhat_setBalance", [address, "0xFFFFFFFFFFFFFFFFFFFFF"]) - - // user wallet and address - const userWallet = ethers.Wallet.createRandom().connect(ethers.provider); - const userAddress = await userWallet.getAddress(); - - // add a ton of fake money to the user wallet - ethers.provider.send("hardhat_setBalance", [userAddress, "0xFFFFFFFFFFFFFFFFFFFFF"]) - - // create the event - const tmp = await vendor_contract_instance.create_new_event("test", address, 2, 0, ticket_cost); - - // attach the contract to the user wallet - // this means when we call the contracts functions the - // sender (signer) will be the user wallet - const user_contract_instance = vendor_contract_instance.connect(userWallet) - - const vendor_balance_before = await ethers.provider.getBalance(address); - - // buy the tickets (way too much money give here) - const resp = await user_contract_instance.buy_tickets("test", [0], {value: ethers.parseEther("1")}); - const resp2 = await user_contract_instance.buy_tickets("test", [1], {value: ethers.parseEther("1")}); - - const vendor_balance_after = await ethers.provider.getBalance(address); - - // check that the vendor wallet gained the correct amount of money - expect(vendor_balance_after - vendor_balance_before).is.equal(ticket_cost*2); - }) - - // checks that the vendor is paid properly when mutliple users buy a ticket - it("properly pays the vendor when multiple users buy a ticket", async () => { - const init_contract = await loadFixture(deployOne); - - // randomly calculate cost of the ticket - let ticket_cost = genRandom(5, 100000); - - // vendor wallet and address - const wallet = ethers.Wallet.createRandom().connect(ethers.provider); - const address = await wallet.getAddress(); - - // add a ton of fake money to the vendor wallet - const vendor_contract_instance = init_contract.connect(wallet); - - ethers.provider.send("hardhat_setBalance", [address, "0xFFFFFFFFFFFFFFFFFFFFF"]) - - // user wallet and address - const userWallet = ethers.Wallet.createRandom().connect(ethers.provider); - const userAddress = await userWallet.getAddress(); - - // add a ton of fake money to the user wallet - ethers.provider.send("hardhat_setBalance", [userAddress, "0xFFFFFFFFFFFFFFFFFFFFF"]) - - // second user wallet and address - const userWallet2 = ethers.Wallet.createRandom().connect(ethers.provider) - const userAddress2 = await userWallet2.getAddress() - - // add a ton of fake money to the second user wallet - ethers.provider.send("hardhat_setBalance", [userAddress2, "0xFFFFFFFFFFFFFFFFFFFFF"]) - - // create the event - const tmp = await vendor_contract_instance.create_new_event("test", address, 2, 0, ticket_cost); - // attach the contract to the user wallet - // this means when we call the contracts functions the - // sender (signer) will be the user wallet - const user_contract_instance = vendor_contract_instance.connect(userWallet); - - const vendor_balance_before = await ethers.provider.getBalance(address); - - // buy the tickets (way too much money give here) - const resp = await user_contract_instance.buy_tickets("test", [0], {value: ethers.parseEther("1")}); - - const user2_contract_instance = user_contract_instance.connect(userWallet2); - - const resp2 = await user2_contract_instance.buy_tickets("test", [1], {value: ethers.parseEther("1")}); - - const vendor_balance_after = await ethers.provider.getBalance(address); - - // check that the vendor wallet gained the correct amount of money - expect(vendor_balance_after - vendor_balance_before).is.equal(ticket_cost*2); - }) - - // checks that the vendor is paid properly when mutliple users buy multiple tickets - it("properly pays the vendor when multiple users buy multiple tickets", async () => { - const init_contract = await loadFixture(deployOne); - - // randomly calculate cost of the ticket - let ticket_cost = genRandom(5, 100000); - - // vendor wallet and address - const wallet = ethers.Wallet.createRandom().connect(ethers.provider); - const address = await wallet.getAddress(); - - // add a ton of fake money to the vendor wallet - const vendor_contract_instance = init_contract.connect(wallet); - - ethers.provider.send("hardhat_setBalance", [address, "0xFFFFFFFFFFFFFFFFFFFFF"]) - - // user wallet and address - const userWallet = ethers.Wallet.createRandom().connect(ethers.provider); - const userAddress = await userWallet.getAddress(); - - // add a ton of fake money to the user wallet - ethers.provider.send("hardhat_setBalance", [userAddress, "0xFFFFFFFFFFFFFFFFFFFFF"]) - - // second user wallet and address - const userWallet2 = ethers.Wallet.createRandom().connect(ethers.provider) - const userAddress2 = await userWallet2.getAddress() - - // add a ton of fake money to the second user wallet - ethers.provider.send("hardhat_setBalance", [userAddress2, "0xFFFFFFFFFFFFFFFFFFFFF"]) - - // create the event - const tmp = await vendor_contract_instance.create_new_event("test", address, 4, 0, ticket_cost); - - // attach the contract to the user wallet - // this means when we call the contracts functions the - // sender (signer) will be the user wallet - const user_contract_instance = vendor_contract_instance.connect(userWallet); - - const vendor_balance_before = await ethers.provider.getBalance(address); - - // buy the tickets (way too much money give here) - const resp = await user_contract_instance.buy_tickets("test", [0,1], {value: ethers.parseEther("1")}); - - const user2_contract_instance = user_contract_instance.connect(userWallet2); - - const resp2 = await user2_contract_instance.buy_tickets("test", [2,3], {value: ethers.parseEther("1")}); - - const vendor_balance_after = await ethers.provider.getBalance(address); - - // check that the vendor wallet gained the correct amount of money - expect(vendor_balance_after - vendor_balance_before).is.equal(ticket_cost*4); - }) - - it("doesn't try to double sell a ticket in a batch event", async() => { - const init_contract = await loadFixture(deployOne); - - // randomly calculate cost of the ticket - let ticket_cost = genRandom(5, 100000); - - // vendor wallet and address - const wallet = ethers.Wallet.createRandom().connect(ethers.provider); - const address = await wallet.getAddress(); - - // add a ton of fake money to the vendor wallet - const vendor_contract_instance = init_contract.connect(wallet); - - ethers.provider.send("hardhat_setBalance", [address, "0xFFFFFFFFFFFFFFFFFFFFF"]) - - // user wallet and address - const userWallet = ethers.Wallet.createRandom().connect(ethers.provider); - const userAddress = await userWallet.getAddress(); - - // add a ton of fake money to the user wallet - ethers.provider.send("hardhat_setBalance", [userAddress, "0xFFFFFFFFFFFFFFFFFFFFF"]) - - // second user wallet and address - const userWallet2 = ethers.Wallet.createRandom().connect(ethers.provider) - const userAddress2 = await userWallet2.getAddress() - - // add a ton of fake money to the second user wallet - ethers.provider.send("hardhat_setBalance", [userAddress2, "0xFFFFFFFFFFFFFFFFFFFFF"]) - - // create the event - const tmp = await vendor_contract_instance.create_new_event("test", address, 4, 0, ticket_cost); - - // attach the contract to the user wallet - // this means when we call the contracts functions the - // sender (signer) will be the user wallet - const user_contract_instance = vendor_contract_instance.connect(userWallet); - - const vendor_balance_before = await ethers.provider.getBalance(address); - - // buy the tickets (way too much money give here) - const resp = await user_contract_instance.buy_tickets("test", [0,1], {value: ethers.parseEther("1")}); - - const user2_contract_instance = user_contract_instance.connect(userWallet2); - - expect(user2_contract_instance.buy_tickets("test", [1,2], {value: ethers.parseEther("1")})).to.rejectedWith(Error); - - const vendor_balance_after = await ethers.provider.getBalance(address); - - // check that the vendor wallet gained the correct amount of money - expect(vendor_balance_after - vendor_balance_before).is.equal(ticket_cost*2); - }) - }) - - // so the goal here is to have random number of vendors generate a random - // number of events with a random numbers of tickets and have a random number of clients buy - // a random number of tickets from a random event and then check that the vendor was payed correctly and - // that the user owns the correct tickets - // describe("Final Overarching Test", async function () { - // it("should work great", async () => { - // // gen a ton of random values - // let number_vendors = genRandom(2, 20); - // let number_clients = number_vendors; - - // let vendor_data = Array(); - // let vendor_event_nums = Array(); - // let total_bought_from_vendor = Array(number_vendors).fill(0); - // let vendor_before_balance = Array(number_vendors); - // let vendor_after_balance = Array(number_vendors); - - // // get the contract - // let contract = await loadFixture(deployOne); - - // // create the vendors - // let vendors = Array(number_vendors); - - // // setup the vendors - // for(let i = 0; i < number_vendors; i++) { - // let number_events = genRandom(1,20); - // vendor_event_nums.push(number_events); - - // let tmp_array = Array(); - - // vendors[i] = ethers.Wallet.createRandom().connect(ethers.provider); - // let address = await vendors[i].getAddress(); - - // // give the vendor some money so it can generate tickets - // ethers.provider.send("hardhat_setBalance", [address, "0xFFFFFFFFFFFFFFFFFFFFF"]) - - // let vendor_contract = contract.connect(vendors[i]); + let client_data = Array(); + let clients = Array(number_clients); + + let client_vendor_mapping = Array.from( + { length: number_vendors }, + (_, i) => i + 1 + ) + .sort(() => Math.random() - 0.5) + .map((num) => num - 1); + + // setup the clients and have them buy + for (let i = 0; i < number_clients; i++) { + let num_events = vendor_event_nums[client_vendor_mapping[i]]; + let number_events_to_purchase_from = genRandom(1, num_events); + + // long line but basically: + // makes list from 0->num_events then randomly pulls number_events_to_purchase_from events from it + let events_index_array = getRandomElements( + Array.from({ length: num_events }, (_, i) => i + 1).map( + (num) => num - 1 + ), + number_events_to_purchase_from + ); + + clients[i] = ethers.Wallet.createRandom().connect(ethers.provider); + let address = await clients[i].getAddress(); + + // give the client some money so it can purchase tickets + ethers.provider.send("hardhat_setBalance", [ + address, + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + ]); + + let client_contract = contract.connect(clients[i]); + + // gotta figure out our ids now (fuck) + // after a 1.5 hour excursion that works (yay!) + let event_ticket_purchases = Array(); + for (let j = 0; j < number_events_to_purchase_from; j++) { + let event_data = + vendor_data[client_vendor_mapping[i]][events_index_array[j]]; + //console.log(event_data); + let num_tickets_to_purchase = genRandom( + 1, + event_data["number_tickets"] + ); + + let tickets_to_purchase = [ + ...( + await client_contract.get_event_ids(event_data["event_name"]) + )[0].slice(0, num_tickets_to_purchase), + ]; + + let local_cost = + num_tickets_to_purchase * event_data["ticket_cost"]; + // update total for total money vendor should have + total_bought_from_vendor[client_vendor_mapping[i]] += local_cost; + + await client_contract.buy_tickets( + event_data["event_name"], + tickets_to_purchase, + { value: ethers.parseEther("1") + BigInt(local_cost) } + ); + + event_ticket_purchases.push(tickets_to_purchase); + } + + client_data.push({ + number_events_to_purchase_from, + event_ticket_purchases, + }); + } - // for(let j = 0; j < number_events; j++) { - // let ticket_cost = genRandom(5,20000); - // let number_tickets = genRandom(1,500); - // let event_name = `vendor ${i} event ${j}`; - - // await vendor_contract.create_new_event(event_name, `i am vendor ${i}`, number_tickets, 0, ticket_cost); - - // tmp_array.push({ticket_cost, number_tickets, event_name}); - // } + // get the vendors balance after the transaction + for (let i = 0; i < number_vendors; i++) { + vendor_after_balance[i] = await ethers.provider.getBalance( + await vendors[i].getAddress() + ); + } - // vendor_before_balance[i] = await ethers.provider.getBalance(address); - - // vendor_data.push(tmp_array); - // } + // make sure all the vendors got the right amount of money + for (let i = 0; i < number_vendors; i++) { + let diff = vendor_after_balance[i] - vendor_before_balance[i]; - // let client_data = Array(); - // let clients = Array(number_clients); + expect(diff).to.equal(total_bought_from_vendor[i]); + } - // let client_vendor_mapping = Array.from({length: number_vendors}, (_, i) => i + 1).sort(() => Math.random() - 0.5).map(num => num-1); - - // // setup the clients and have them buy - // for (let i = 0; i < number_clients; i++) { - // let num_events = vendor_event_nums[client_vendor_mapping[i]]; - // let number_events_to_purchase_from = genRandom(1, num_events); - - // // long line but basically: - // // makes list from 0->num_events then randomly pulls number_events_to_purchase_from events from it - // let events_index_array = getRandomElements(Array.from({length: num_events}, (_, i) => i + 1).map(num => num-1), number_events_to_purchase_from); - - // clients[i] = ethers.Wallet.createRandom().connect(ethers.provider); - // let address = await clients[i].getAddress(); - - // // give the client some money so it can purchase tickets - // ethers.provider.send("hardhat_setBalance", [address, "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"]) - - // let client_contract = contract.connect(clients[i]); - - // // gotta figure out our ids now (fuck) - // // after a 1.5 hour excursion that works (yay!) - // let event_ticket_purchases = Array(); - // for (let j = 0; j < number_events_to_purchase_from; j++) { - - // let event_data = vendor_data[client_vendor_mapping[i]][events_index_array[j]]; - // //console.log(event_data); - // let num_tickets_to_purchase = genRandom(1, event_data['number_tickets']); - - // let tickets_to_purchase = [...(await client_contract.get_event_ids(event_data['event_name']))[0].slice(0, num_tickets_to_purchase)]; - - // let local_cost = num_tickets_to_purchase * event_data['ticket_cost']; - // // update total for total money vendor should have - // total_bought_from_vendor[client_vendor_mapping[i]] += local_cost; - - // await client_contract.buy_tickets(event_data['event_name'], tickets_to_purchase, {value: ethers.parseEther("1") + BigInt(local_cost)}); - - // event_ticket_purchases.push(tickets_to_purchase); - // } - - // client_data.push({number_events_to_purchase_from, event_ticket_purchases}); - // } - - // // get the vendors balance after the transaction - // for (let i = 0; i < number_vendors; i++) { - // vendor_after_balance[i] = await ethers.provider.getBalance(await vendors[i].getAddress()); - // } - - // // make sure all the vendors got the right amount of money - // for (let i = 0; i < number_vendors; i++) { - // let diff = vendor_after_balance[i] - vendor_before_balance[i]; - - // expect(diff).to.equal(total_bought_from_vendor[i]); - // } - - // // make sure the clients own all the tickets they bought - // for (let i = 0; i < clients.length; i++) { - // let big_ol_list = client_data[i]['event_ticket_purchases']; - - // for (let j = 0; j < big_ol_list.length; j++) { - // expect(await contract.balanceOfBatch(Array(big_ol_list[j].length).fill(await clients[i].getAddress()), big_ol_list[j])).to.eql(Array(big_ol_list[j].length).fill(1n)); - // } - // } - // }) - // }) - }) -}) + // make sure the clients own all the tickets they bought + for (let i = 0; i < clients.length; i++) { + let big_ol_list = client_data[i]["event_ticket_purchases"]; + + for (let j = 0; j < big_ol_list.length; j++) { + expect( + await contract.balanceOfBatch( + Array(big_ol_list[j].length).fill( + await clients[i].getAddress() + ), + big_ol_list[j] + ) + ).to.eql(Array(big_ol_list[j].length).fill(1n)); + } + } + }); + }); + }); +});