From c12fd112ba3096b838fe2f405e58e2429146a14c Mon Sep 17 00:00:00 2001 From: adiusz Date: Sat, 21 Sep 2024 20:22:29 +0200 Subject: [PATCH 1/2] ticket:multi royalties receivers, send fn; fix sh script --- copy-artifacts-to-app.sh | 6 ++- ticket/src/lib.cairo | 111 +++++++++++++++++++++++++++++++++++---- 2 files changed, 104 insertions(+), 13 deletions(-) diff --git a/copy-artifacts-to-app.sh b/copy-artifacts-to-app.sh index c2a7162..798bf6e 100755 --- a/copy-artifacts-to-app.sh +++ b/copy-artifacts-to-app.sh @@ -6,7 +6,7 @@ # $we_are_here blessed-dashboard # Base directories -app_artifacts_dir="../blessed-dashboard/src/contracts/artifacts" +app_artifacts_dir="../blessed-api/src/contracts/artifacts" # Loop through each folder in the blessed-cairo-contracts directory for dir in */; do @@ -28,8 +28,10 @@ for dir in */; do # Copy the found JSON file to the artifacts directory with the new name new_file_path="$app_artifacts_dir/${contract_name}.json" + echo "🗃️ JSON_FILE IS: $json_file" + echo "🛣️ NEW_FILE_ATH IS: $new_file_path" cp "$json_file" "$new_file_path" - echo "📝 Copied to: $new_file_path" + echo "✅ Copied to: $new_file_path" done echo "________________________" diff --git a/ticket/src/lib.cairo b/ticket/src/lib.cairo index 07e9751..7eef03a 100644 --- a/ticket/src/lib.cairo +++ b/ticket/src/lib.cairo @@ -82,6 +82,9 @@ mod ERC1155EventTicket { pub next_token_id: u256, pub event_start: u64, pub event_end: u64, + pub royalties_map: LegacyMap, + pub royalties_receivers: LegacyMap, + pub royalties_receivers_count: u32, #[substorage(v0)] erc1155: ERC1155Component::Storage, #[substorage(v0)] @@ -165,15 +168,16 @@ mod ERC1155EventTicket { owner: ContractAddress, ticket_price: u256, ticket_supply: u256, - royalties: u8, + royalties_receivers: Array<(ContractAddress, u8)>, erc20_address: ContractAddress, ticket_type: felt252, event_start: u64, event_end: u64, ) { - assert(1 <= royalties && royalties <= 99, 'must be between 1 and 99'); + // assert(1 <= royalties && royalties <= 99, 'must be between 1 and 99'); assert(event_start > get_block_timestamp(), 'event_start < now'); assert(event_end > event_start, 'event_end < event_start'); + assert(royalties_receivers.len() == 0 || ticket_price > 10_u256, 'Price must be > 10 if royalties'); let ticket_type_value = if ticket_type == 'free' { @@ -193,7 +197,26 @@ mod ERC1155EventTicket { self.next_token_id.write(1); self.ticket_price.write(ticket_price); self.ticket_supply.write(ticket_supply); - self.royalties.write(royalties); + // self.royalties.write(royalties); + + let mut total_royalties: u8 = 0; + let mut count: u32 = 0; + let mut royalties_receivers = royalties_receivers; + loop { + match royalties_receivers.pop_front() { + Option::Some((address, percentage)) => { + total_royalties += percentage; + assert(total_royalties <= 99, 'Total royalties must be <= 99%'); + self.royalties_map.write(address, percentage); + self.royalties_receivers.write(count, address); + count += 1; + }, + Option::None => { break; }, + }; + }; + self.royalties_receivers_count.write(count); + + // dsadasdsa self.erc20_address.write(erc20_address); self.erc1155.initializer(""); self.ownable.initializer(owner); @@ -211,6 +234,27 @@ mod ERC1155EventTicket { // self.mint_ticket(starknet::contract_address_const::<0x0384753535a8f4febe864e07d6c2bf0ea7be049cfaa1c5ebe9106b467b406a8e>()); } + // 🏗️ TODO: probably this will be for delete + // #[external(v0)] + // fn set_royalties(ref self: ContractState, royalties_receivers: Array<(ContractAddress, u8)>) { + // let mut total_royalties: u8 = 0; + // let mut count: u32 = 0; + // let mut royalties_receivers = royalties_receivers; + // loop { + // match royalties_receivers.pop_front() { + // Option::Some((address, percentage)) => { + // total_royalties += percentage; + // assert(total_royalties <= 99, 'Total royalties must be <= 99%'); + // self.royalties_map.write(address, percentage); + // self.royalties_receivers.write(count, address); + // count += 1; + // }, + // Option::None => { break; }, + // }; + // }; + // self.royalties_receivers_count.write(count); + // } + #[generate_trait] #[abi(per_item)] impl ExternalImpl of ExternalTrait { @@ -262,28 +306,61 @@ mod ERC1155EventTicket { } #[external(v0)] - fn get_ticket(ref self: ContractState) { + fn get(ref self: ContractState) { let caller = get_caller_address(); let ticket_type = self.ticket_type.read(); let caller_owned_token_id = self.ticket_balances.read(caller); assert(caller_owned_token_id == 0, 'You already have a ticket'); + let mut erc20_address = self.erc20_address.read(); match ticket_type { EventType::Free => { self.mint_ticket(caller); }, - EventType::Refundable | EventType::Paid => { - let mut erc20_address = self.erc20_address.read(); + EventType::Refundable => { let caller_balance = IERC20::balance_of(@erc20_address, caller); assert(caller_balance >= self.ticket_price.read(), 'Insufficient balance'); let allowed_amount = IERC20::allowance(@erc20_address, caller, starknet::get_contract_address()); assert(allowed_amount >= self.ticket_price.read(), 'Insufficient allowance'); + IERC20::transferFrom(ref erc20_address, caller, starknet::get_contract_address(), self.ticket_price.read()); self.mint_ticket(caller); }, + EventType::Paid => { + let mut remaining_amount = self.ticket_price.read(); + let receivers_count = self.royalties_receivers_count.read(); + + let mut i: u32 = 0; + loop { + if i >= receivers_count { + break; + } + let receiver = self.royalties_receivers.read(i); + let royalty_percentage = self.royalties_map.read(receiver); + let royalty_amount = (self.ticket_price.read() * royalty_percentage.into()) / 100_u256; + if royalty_amount > 0 { + IERC20::transferFrom(ref erc20_address, caller, receiver, royalty_amount); + remaining_amount -= royalty_amount; + } + i += 1; + }; + + // Transfer remaining amount to owner + if remaining_amount > 0 { + let owner = self.ownable.owner(); + IERC20::transferFrom(ref erc20_address, caller, owner, remaining_amount); + } + + self.mint_ticket(caller); + } } } + #[external(v0)] + fn send(ref self: ContractState, to: ContractAddress) { + self.mint_ticket(to) + } + #[external(v0)] fn get_ticket_type_felt252(self: @ContractState) -> felt252 { match self.ticket_type.read() { @@ -448,11 +525,6 @@ mod ERC1155EventTicket { self.ticket_supply.read() } - #[external(v0)] - fn get_royalties(self: @ContractState) -> u8 { - self.royalties.read() - } - #[external(v0)] fn get_wallet_token_id(self: @ContractState, wallet: ContractAddress) -> u256 { self.ticket_balances.read(wallet) @@ -463,4 +535,21 @@ mod ERC1155EventTicket { let (token_id, price) = self.ticket_listings.read(wallet); (token_id, price) } + + #[external(v0)] + fn get_royalties(self: @ContractState) -> Array<(ContractAddress, u8)> { + let mut result = ArrayTrait::new(); + let receivers_count = self.royalties_receivers_count.read(); + let mut i: u32 = 0; + loop { + if i >= receivers_count { + break; + } + let receiver = self.royalties_receivers.read(i); + let percentage = self.royalties_map.read(receiver); + result.append((receiver, percentage)); + i += 1; + }; + result + } } From 40253d8f379b19404f7ad99a59b9439a24ae460e Mon Sep 17 00:00:00 2001 From: adiusz Date: Sun, 22 Sep 2024 12:18:59 +0200 Subject: [PATCH 2/2] send is only for owner; make erc20_addr nod mandatory for free events --- ticket/src/lib.cairo | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/ticket/src/lib.cairo b/ticket/src/lib.cairo index 7eef03a..7b7fa54 100644 --- a/ticket/src/lib.cairo +++ b/ticket/src/lib.cairo @@ -174,13 +174,11 @@ mod ERC1155EventTicket { event_start: u64, event_end: u64, ) { - // assert(1 <= royalties && royalties <= 99, 'must be between 1 and 99'); assert(event_start > get_block_timestamp(), 'event_start < now'); assert(event_end > event_start, 'event_end < event_start'); assert(royalties_receivers.len() == 0 || ticket_price > 10_u256, 'Price must be > 10 if royalties'); - - let ticket_type_value = - if ticket_type == 'free' { + + let ticket_type_value = if ticket_type == 'free' { EventType::Free } else if ticket_type == 'refundable' { EventType::Refundable @@ -191,13 +189,13 @@ mod ERC1155EventTicket { error_msg.append('free | refundable | paid'); panic(error_msg) }; + self.ticket_type.write(ticket_type_value); self.event_start.write(event_start); self.event_end.write(event_end); self.next_token_id.write(1); self.ticket_price.write(ticket_price); self.ticket_supply.write(ticket_supply); - // self.royalties.write(royalties); let mut total_royalties: u8 = 0; let mut count: u32 = 0; @@ -216,19 +214,19 @@ mod ERC1155EventTicket { }; self.royalties_receivers_count.write(count); - // dsadasdsa - self.erc20_address.write(erc20_address); self.erc1155.initializer(""); self.ownable.initializer(owner); - let total_approval_amount = self.ticket_price.read() * self.ticket_supply.read(); - let mut erc20_address = self.erc20_address.read(); - IERC20::approve( - ref erc20_address, - starknet::get_contract_address(), - total_approval_amount - ); - + if ticket_type_value != EventType::Free { + self.erc20_address.write(erc20_address); + let total_approval_amount = self.ticket_price.read() * self.ticket_supply.read(); + let mut erc20_address = self.erc20_address.read(); + IERC20::approve( + ref erc20_address, + starknet::get_contract_address(), + total_approval_amount + ); + } // 🏗️ TODO: delete this ⬇️ it's for simpler testing // self.mint_ticket(owner); // self.mint_ticket(starknet::contract_address_const::<0x0384753535a8f4febe864e07d6c2bf0ea7be049cfaa1c5ebe9106b467b406a8e>()); @@ -311,13 +309,13 @@ mod ERC1155EventTicket { let ticket_type = self.ticket_type.read(); let caller_owned_token_id = self.ticket_balances.read(caller); assert(caller_owned_token_id == 0, 'You already have a ticket'); - let mut erc20_address = self.erc20_address.read(); - + match ticket_type { EventType::Free => { self.mint_ticket(caller); }, EventType::Refundable => { + let mut erc20_address = self.erc20_address.read(); let caller_balance = IERC20::balance_of(@erc20_address, caller); assert(caller_balance >= self.ticket_price.read(), 'Insufficient balance'); let allowed_amount = IERC20::allowance(@erc20_address, caller, starknet::get_contract_address()); @@ -327,6 +325,7 @@ mod ERC1155EventTicket { self.mint_ticket(caller); }, EventType::Paid => { + let mut erc20_address = self.erc20_address.read(); let mut remaining_amount = self.ticket_price.read(); let receivers_count = self.royalties_receivers_count.read(); @@ -358,6 +357,7 @@ mod ERC1155EventTicket { #[external(v0)] fn send(ref self: ContractState, to: ContractAddress) { + self.ownable.assert_only_owner(); self.mint_ticket(to) } @@ -431,6 +431,8 @@ mod ERC1155EventTicket { #[external(v0)] fn list(ref self: ContractState, token_id: u256, price: u256) { + assert(self.ticket_type.read() != EventType::Free, 'Not available for free tickets'); + let caller = get_caller_address(); assert(self.erc1155.balance_of(caller, token_id) > 0, 'Not the token owner'); let (listed_token_id, _) = self.ticket_listings.read(caller); @@ -445,6 +447,8 @@ mod ERC1155EventTicket { #[external(v0)] fn delist(ref self: ContractState, token_id: u256) { + assert(self.ticket_type.read() != EventType::Free, 'Not available for free tickets'); + let caller = get_caller_address(); let (listed_token_id, _) = self.ticket_listings.read(caller); assert(listed_token_id == token_id, 'Token not listed '); @@ -456,6 +460,8 @@ mod ERC1155EventTicket { #[external(v0)] fn buy(ref self: ContractState, seller: ContractAddress, token_id: u256) { + assert(self.ticket_type.read() != EventType::Free, 'Not available for free tickets'); + // before calling this, user needs to approve this contract to spend their ERC20 tokens let buyer = get_caller_address(); let (listed_token_id, price) = self.ticket_listings.read(seller); @@ -516,7 +522,7 @@ mod ERC1155EventTicket { } #[external(v0)] - fn get_ticket_price(self: @ContractState) -> u256 { + fn get_ticket_price(self: @ContractState) -> u256 { self.ticket_price.read() }