From 0a551a2727b550e62f17dbed12e5bbf49004f166 Mon Sep 17 00:00:00 2001 From: Brian Sin Date: Tue, 20 Aug 2024 23:18:25 +0700 Subject: [PATCH] update staking pool, flexdrop --- .../interfaces/IFlexStakingPool.cairo | 3 +- .../openedition/ERC721_open_edition.cairo | 26 +++-- .../ERC721_open_edition_multi_metadata.cairo | 24 +++-- .../marketplace/openedition/FlexDrop.cairo | 95 +++++++++++++++---- .../openedition/interfaces/IFlexDrop.cairo | 1 + .../INonFungibleFlexDropToken.cairo | 8 +- .../stakingpool/FlexStakingPool.cairo | 21 +++- 7 files changed, 136 insertions(+), 42 deletions(-) diff --git a/flex_marketplace/src/marketplace/interfaces/IFlexStakingPool.cairo b/flex_marketplace/src/marketplace/interfaces/IFlexStakingPool.cairo index fe17568..e5d17f5 100644 --- a/flex_marketplace/src/marketplace/interfaces/IFlexStakingPool.cairo +++ b/flex_marketplace/src/marketplace/interfaces/IFlexStakingPool.cairo @@ -4,7 +4,8 @@ use starknet::ContractAddress; trait IFlexStakingPool { fn stakeNFT(ref self: TContractState, collection: ContractAddress, tokenId: u256); fn unstakeNFT(ref self: TContractState, collection: ContractAddress, tokenId: u256); - fn getUserPoint( + fn getUserPointByItem( self: @TContractState, user: ContractAddress, nftCollection: ContractAddress, tokenId: u256 ) -> u256; + fn getUserTotalPoint(self: @TContractState, user: ContractAddress,) -> u256; } diff --git a/flex_marketplace/src/marketplace/openedition/ERC721_open_edition.cairo b/flex_marketplace/src/marketplace/openedition/ERC721_open_edition.cairo index 21a98c6..22d8bb2 100644 --- a/flex_marketplace/src/marketplace/openedition/ERC721_open_edition.cairo +++ b/flex_marketplace/src/marketplace/openedition/ERC721_open_edition.cairo @@ -65,8 +65,8 @@ mod ERC721OpenEdition { // mapping allowed FlexDrop contract allowed_flex_drop: LegacyMap::, total_minted: u64, - // mapping total minted per minter - total_minted_per_wallet: LegacyMap::, + // (address, phase id) => mapping total minted per minter + total_minted_per_wallet: LegacyMap::<(ContractAddress, u64), u64>, // Track the enumerated allowed FlexDrop address enumerated_allowed_flex_drop: List, current_phase_id: u64, @@ -173,12 +173,14 @@ mod ERC721OpenEdition { } // mint tokens, restricted to the FlexDrop contract - fn mint_flex_drop(ref self: ContractState, minter: ContractAddress, quantity: u64) { + fn mint_flex_drop( + ref self: ContractState, minter: ContractAddress, phase_id: u64, quantity: u64 + ) { self.reentrancy_guard.start(); let flex_drop = get_caller_address(); self.assert_allowed_flex_drop(flex_drop); - self.safe_mint_flex_drop(minter, quantity); + self.safe_mint_flex_drop(minter, phase_id, quantity); self.reentrancy_guard.end(); } @@ -288,10 +290,12 @@ mod ERC721OpenEdition { } } - fn get_mint_state(self: @ContractState, minter: ContractAddress) -> (u64, u64, u64) { - let total_minted = self.total_minted_per_wallet.read(minter); + fn get_mint_state( + self: @ContractState, minter: ContractAddress, phase_id: u64 + ) -> (u64, u64, u64) { + let total_minted = self.total_minted_per_wallet.read((minter, phase_id)); let current_total_supply = self.get_total_minted(); - (total_minted, current_total_supply, BoundedU64::max() - 1) + (total_minted, current_total_supply, self.erc721.total_supply()) } fn get_current_token_id(self: @ContractState) -> u256 { @@ -305,12 +309,16 @@ mod ERC721OpenEdition { #[generate_trait] impl InternalFlexDropToken of InternalFlexDropTokenTrait { - fn safe_mint_flex_drop(ref self: ContractState, to: ContractAddress, quantity: u64) { + fn safe_mint_flex_drop( + ref self: ContractState, to: ContractAddress, phase_id: u64, quantity: u64 + ) { let mut current_token_id = self.get_current_token_id(); self .total_minted_per_wallet - .write(to, self.total_minted_per_wallet.read(to) + quantity); + .write( + (to, phase_id), self.total_minted_per_wallet.read((to, phase_id)) + quantity + ); self.current_token_id.write(current_token_id + quantity.into()); self.total_minted.write(self.get_total_minted() + quantity); diff --git a/flex_marketplace/src/marketplace/openedition/ERC721_open_edition_multi_metadata.cairo b/flex_marketplace/src/marketplace/openedition/ERC721_open_edition_multi_metadata.cairo index 0b4838e..6156739 100644 --- a/flex_marketplace/src/marketplace/openedition/ERC721_open_edition_multi_metadata.cairo +++ b/flex_marketplace/src/marketplace/openedition/ERC721_open_edition_multi_metadata.cairo @@ -66,8 +66,8 @@ mod ERC721OpenEditionMultiMetadata { // mapping allowed FlexDrop contract allowed_flex_drop: LegacyMap::, total_minted: u64, - // mapping total minted per minter - total_minted_per_wallet: LegacyMap::, + // (address, phase id) => mapping total minted per minter + total_minted_per_wallet: LegacyMap::<(ContractAddress, u64), u64>, // Track the enumerated allowed FlexDrop address enumerated_allowed_flex_drop: List, current_phase_id: u64, @@ -175,12 +175,14 @@ mod ERC721OpenEditionMultiMetadata { } // mint tokens, restricted to the FlexDrop contract - fn mint_flex_drop(ref self: ContractState, minter: ContractAddress, quantity: u64) { + fn mint_flex_drop( + ref self: ContractState, minter: ContractAddress, phase_id: u64, quantity: u64 + ) { self.reentrancy_guard.start(); let flex_drop = get_caller_address(); self.assert_allowed_flex_drop(flex_drop); - self.safe_mint_flex_drop(minter, quantity); + self.safe_mint_flex_drop(minter, phase_id, quantity); self.reentrancy_guard.end(); } @@ -291,8 +293,10 @@ mod ERC721OpenEditionMultiMetadata { } // return (number minted, current total supply) - fn get_mint_state(self: @ContractState, minter: ContractAddress) -> (u64, u64, u64) { - let total_minted = self.total_minted_per_wallet.read(minter); + fn get_mint_state( + self: @ContractState, minter: ContractAddress, phase_id: u64 + ) -> (u64, u64, u64) { + let total_minted = self.total_minted_per_wallet.read((minter, phase_id)); let current_total_supply = self.get_total_minted(); (total_minted, current_total_supply, self.erc721.total_supply()) } @@ -308,12 +312,16 @@ mod ERC721OpenEditionMultiMetadata { #[generate_trait] impl InternalFlexDropToken of InternalFlexDropTokenTrait { - fn safe_mint_flex_drop(ref self: ContractState, to: ContractAddress, quantity: u64) { + fn safe_mint_flex_drop( + ref self: ContractState, to: ContractAddress, phase_id: u64, quantity: u64 + ) { let mut current_token_id = self.get_current_token_id(); self .total_minted_per_wallet - .write(to, self.total_minted_per_wallet.read(to) + quantity); + .write( + (to, phase_id), self.total_minted_per_wallet.read((to, phase_id)) + quantity + ); self.current_token_id.write(current_token_id + quantity.into()); self.total_minted.write(self.get_total_minted() + quantity); diff --git a/flex_marketplace/src/marketplace/openedition/FlexDrop.cairo b/flex_marketplace/src/marketplace/openedition/FlexDrop.cairo index ac0b09c..d499494 100644 --- a/flex_marketplace/src/marketplace/openedition/FlexDrop.cairo +++ b/flex_marketplace/src/marketplace/openedition/FlexDrop.cairo @@ -48,6 +48,8 @@ mod FlexDrop { allowed_payer: LegacyMap::<(ContractAddress, ContractAddress), bool>, // protocol fee mint fee_mint: u256, + // protocol fee mint when creator set mint price is 0 + fee_mint_when_zero_price: u256, // protocal fee currency fee_currency: ContractAddress, // start new phase fee @@ -91,12 +93,14 @@ mod FlexDrop { struct FlexDropMinted { #[key] nft_address: ContractAddress, + phase_id: u64, minter: ContractAddress, fee_recipient: ContractAddress, payer: ContractAddress, quantity_minted: u64, total_mint_price: u256, fee_mint: u256, + is_warpcast: bool } #[derive(Drop, starknet::Event)] @@ -137,6 +141,7 @@ mod FlexDrop { currency_manager: ContractAddress, fee_currency: ContractAddress, fee_mint: u256, + fee_mint_when_zero_price: u256, new_phase_fee: u256, domain_hash: felt252, validator: ContractAddress, @@ -146,6 +151,7 @@ mod FlexDrop { self.ownable.initializer(owner); self.fee_currency.write(fee_currency); self.fee_mint.write(fee_mint); + self.fee_mint_when_zero_price.write(fee_mint_when_zero_price); self.new_phase_fee.write(new_phase_fee); self.validator.write(validator); self.domain_hash.write(domain_hash); @@ -175,6 +181,7 @@ mod FlexDrop { fee_recipient: ContractAddress, minter_if_not_payer: ContractAddress, quantity: u64, + is_warpcast: bool, ) { self.pausable.assert_not_paused(); self.reentrancy.start(); @@ -186,15 +193,15 @@ mod FlexDrop { minter = minter_if_not_payer.clone(); } - let mut is_payer: bool = false; if minter != get_caller_address() { self.assert_allowed_payer(nft_address, get_caller_address()); - is_payer = true; + } else { + assert(!is_warpcast, 'FlexDrop: Method Not Allowed'); } self .assert_valid_mint_quantity( - @nft_address, @minter, quantity, phase_drop.max_mint_per_wallet + @nft_address, @minter, phase_id, quantity, phase_drop.max_mint_per_wallet ); self.assert_allowed_fee_recipient(@fee_recipient); @@ -205,11 +212,13 @@ mod FlexDrop { nft_address, get_caller_address(), minter, - is_payer, + is_warpcast, + phase_id, quantity, phase_drop.currency, total_mint_price, - fee_recipient + fee_recipient, + false ); self.reentrancy.end(); } @@ -251,10 +260,12 @@ mod FlexDrop { whitelist_data.minter, whitelist_data.minter, false, + whitelist_data.phase_id, 1, phase_drop.currency, 0, - fee_recipient + fee_recipient, + true ); self.reentrancy.end(); } @@ -393,6 +404,25 @@ mod FlexDrop { } } + #[external(v0)] + fn change_protocol_fee_mint_when_zero_price( + ref self: ContractState, + new_fee_currency: ContractAddress, + new_fee_mint_when_zero_price: u256 + ) { + self.ownable.assert_only_owner(); + + let old_fee_mint = self.fee_mint_when_zero_price.read(); + if old_fee_mint != new_fee_mint_when_zero_price { + self.fee_mint_when_zero_price.write(new_fee_mint_when_zero_price); + } + + let old_fee_currency = self.fee_currency.read(); + if old_fee_currency != new_fee_currency { + self.fee_currency.write(new_fee_currency); + } + } + #[external(v0)] fn update_protocol_fee_recipients( ref self: ContractState, fee_recipient: ContractAddress, allowed: bool @@ -420,6 +450,11 @@ mod FlexDrop { self.fee_mint.read() } + #[external(v0)] + fn get_fee_mint_when_zero_price(self: @ContractState) -> u256 { + self.fee_mint_when_zero_price.read() + } + #[external(v0)] fn get_new_phase_fee(self: @ContractState) -> u256 { self.new_phase_fee.read() @@ -544,6 +579,7 @@ mod FlexDrop { self: @ContractState, nft_address: @ContractAddress, minter: @ContractAddress, + phase_id: u64, quantity: u64, max_total_mint_per_wallet: u64, ) { @@ -552,7 +588,7 @@ mod FlexDrop { let (total_minted, current_supply, total_supply) = INonFungibleFlexDropTokenDispatcher { contract_address: *nft_address } - .get_mint_state(*minter); + .get_mint_state(*minter, phase_id); assert( total_minted + quantity <= max_total_mint_per_wallet, 'Exceeds maximum total minted' @@ -573,30 +609,44 @@ mod FlexDrop { nft_address: ContractAddress, payer: ContractAddress, minter: ContractAddress, - is_payer: bool, + is_warpcast: bool, + phase_id: u64, quantity: u64, currency_address: ContractAddress, total_mint_price: u256, - fee_recipient: ContractAddress + fee_recipient: ContractAddress, + is_whitelist_mint: bool ) { self .split_payout( - payer, is_payer, nft_address, fee_recipient, currency_address, total_mint_price + payer, + is_warpcast, + nft_address, + fee_recipient, + currency_address, + total_mint_price, + is_whitelist_mint ); INonFungibleFlexDropTokenDispatcher { contract_address: nft_address } - .mint_flex_drop(minter, quantity); + .mint_flex_drop(minter, phase_id, quantity); + let mut fee_mint = self.fee_mint.read(); + if total_mint_price == 0 && !is_whitelist_mint && !is_warpcast { + fee_mint = self.fee_mint_when_zero_price.read(); + } self .emit( FlexDropMinted { nft_address, + phase_id, minter, fee_recipient, payer, quantity_minted: quantity, total_mint_price, - fee_mint: self.fee_mint.read(), + fee_mint, + is_warpcast } ) } @@ -604,21 +654,28 @@ mod FlexDrop { fn split_payout( ref self: ContractState, from: ContractAddress, - is_payer: bool, + is_warpcast: bool, nft_address: ContractAddress, fee_recipient: ContractAddress, currency_address: ContractAddress, - total_mint_price: u256 + total_mint_price: u256, + is_whitelist_mint: bool, ) { let fee_mint = self.fee_mint.read(); - if fee_mint > 0 { - let fee_currency_contract = IERC20Dispatcher { - contract_address: self.fee_currency.read() - }; + let fee_mint_when_zero_price = self.fee_mint_when_zero_price.read(); + let fee_currency_contract = IERC20Dispatcher { + contract_address: self.fee_currency.read() + }; + if total_mint_price == 0 + && fee_mint_when_zero_price > 0 + && !is_whitelist_mint + && !is_warpcast { + fee_currency_contract.transfer_from(from, fee_recipient, fee_mint_when_zero_price); + } else if fee_mint > 0 { fee_currency_contract.transfer_from(from, fee_recipient, fee_mint); } - if total_mint_price > 0 && !is_payer { + if total_mint_price > 0 && !is_warpcast { let currency_contract = IERC20Dispatcher { contract_address: currency_address }; let creator_payout_address = self.creator_payout_address.read(nft_address); assert!( diff --git a/flex_marketplace/src/marketplace/openedition/interfaces/IFlexDrop.cairo b/flex_marketplace/src/marketplace/openedition/interfaces/IFlexDrop.cairo index a4088d8..e41bfa0 100644 --- a/flex_marketplace/src/marketplace/openedition/interfaces/IFlexDrop.cairo +++ b/flex_marketplace/src/marketplace/openedition/interfaces/IFlexDrop.cairo @@ -10,6 +10,7 @@ trait IFlexDrop { fee_recipient: ContractAddress, minter_if_not_payer: ContractAddress, quantity: u64, + is_warpcast: bool, ); fn whitelist_mint( ref self: TContractState, diff --git a/flex_marketplace/src/marketplace/openedition/interfaces/INonFungibleFlexDropToken.cairo b/flex_marketplace/src/marketplace/openedition/interfaces/INonFungibleFlexDropToken.cairo index b761af8..ecc74ec 100644 --- a/flex_marketplace/src/marketplace/openedition/interfaces/INonFungibleFlexDropToken.cairo +++ b/flex_marketplace/src/marketplace/openedition/interfaces/INonFungibleFlexDropToken.cairo @@ -12,7 +12,9 @@ trait INonFungibleFlexDropToken { ref self: TContractState, allowed_flex_drop: Array:: ); // mint tokens, restricted to the FlexDrop contract - fn mint_flex_drop(ref self: TContractState, minter: ContractAddress, quantity: u64); + fn mint_flex_drop( + ref self: TContractState, minter: ContractAddress, phase_id: u64, quantity: u64 + ); fn create_new_phase_drop( ref self: TContractState, flex_drop: ContractAddress, @@ -31,7 +33,9 @@ trait INonFungibleFlexDropToken { ); fn multi_configure(ref self: TContractState, config: MultiConfigureStruct); // return (number minted, current total supply, max supply) - fn get_mint_state(self: @TContractState, minter: ContractAddress) -> (u64, u64, u64); + fn get_mint_state( + self: @TContractState, minter: ContractAddress, phase_id: u64 + ) -> (u64, u64, u64); fn get_current_token_id(self: @TContractState) -> u256; fn get_allowed_flex_drops(self: @TContractState) -> Span::; } diff --git a/flex_marketplace/src/marketplace/stakingpool/FlexStakingPool.cairo b/flex_marketplace/src/marketplace/stakingpool/FlexStakingPool.cairo index 4909a83..569d6ed 100644 --- a/flex_marketplace/src/marketplace/stakingpool/FlexStakingPool.cairo +++ b/flex_marketplace/src/marketplace/stakingpool/FlexStakingPool.cairo @@ -1,6 +1,5 @@ #[starknet::contract] mod FlexStakingPool { - use core::array::ArrayTrait; use flex::marketplace::interfaces::IFlexStakingPool::IFlexStakingPool; use openzeppelin::access::ownable::OwnableComponent; use openzeppelin::token::erc721::interface::{ERC721ABIDispatcher, ERC721ABIDispatcherTrait}; @@ -168,7 +167,7 @@ mod FlexStakingPool { self.reentrancy.end(); } - fn getUserPoint( + fn getUserPointByItem( self: @ContractState, user: ContractAddress, nftCollection: ContractAddress, @@ -176,6 +175,22 @@ mod FlexStakingPool { ) -> u256 { self._calculateTotalReward(user, nftCollection, tokenId) } + + fn getUserTotalPoint(self: @ContractState, user: ContractAddress,) -> u256 { + let items = self.getItemStaked(user); + let mut totalPoints: u256 = 0; + + let mut index = 0; + loop { + if (index == items.len()) { + break totalPoints; + } + + let item = items.at(index); + totalPoints += self._calculateTotalReward(user, *item.collection, *item.tokenId); + index += 1; + } + } } #[abi(per_item)] @@ -287,7 +302,7 @@ mod FlexStakingPool { if (timeUnit > 0 && rewardPerUnitTime > 0) { let stakedPeriod = blockTime - stakedDetail.stakedAt; - point += (stakedPeriod.into() * rewardPerUnitTime) / timeUnit.into(); + point += (stakedPeriod / timeUnit.into()).into() * rewardPerUnitTime.into(); } break point;