From 0efef1e9550a8994a02ac4a9473cca4acaae46b2 Mon Sep 17 00:00:00 2001 From: Hakeem Kazeem Date: Tue, 26 Nov 2024 12:59:24 +0100 Subject: [PATCH 1/9] create_auction_for_username, place_order and test --- .../cairo/.snfoundry_cache/.prev_tests_failed | 14 --- onchain/cairo/src/afk_id/nameservice.cairo | 73 +++++++++++- .../cairo/src/interfaces/nameservice.cairo | 2 + onchain/cairo/src/lib.cairo | 2 - .../cairo/src/tests/nameservice_tests.cairo | 105 ++++++++++++++++++ 5 files changed, 178 insertions(+), 18 deletions(-) diff --git a/onchain/cairo/.snfoundry_cache/.prev_tests_failed b/onchain/cairo/.snfoundry_cache/.prev_tests_failed index 3e280aee..e69de29b 100644 --- a/onchain/cairo/.snfoundry_cache/.prev_tests_failed +++ b/onchain/cairo/.snfoundry_cache/.prev_tests_failed @@ -1,14 +0,0 @@ -afk::tests::launchpad_tests::launchpad_tests::launchpad_test_calculation -afk::tests::launchpad_tests::launchpad_tests::test_create_and_add_liquidity_unrug_liq_without_launchpad_threshold -afk::tests::launchpad_tests::launchpad_tests::test_get_coin_amount_by_quote_amount_for_buy_steps -afk::tests::launchpad_tests::launchpad_tests::test_get_coin_launch -afk::tests::launchpad_tests::launchpad_tests::test_launch_token -afk::tests::launchpad_tests::launchpad_tests::test_add_liquidity_jediswap -afk::tests::launchpad_tests::launchpad_tests::test_sell_coin_when_share_too_low -afk::tests::launchpad_tests::launchpad_tests::test_add_liquidity_ekubo -afk::tests::launchpad_tests::launchpad_tests::test_create_and_add_liquidity_unrug_liq_without_launchpad_but_launch -afk::tests::launchpad_tests::launchpad_tests::test_launch_token_with_uncreated_token -afk::tests::launchpad_tests::launchpad_tests::test_set_protocol_fee_percent_non_admin -afk::tests::launchpad_tests::launchpad_tests::test_create_and_add_liquidity_unrug -afk::tests::launchpad_tests::launchpad_tests::launchpad_end_to_end -afk::tests::launchpad_tests::launchpad_tests::test_launchpad_end_to_end diff --git a/onchain/cairo/src/afk_id/nameservice.cairo b/onchain/cairo/src/afk_id/nameservice.cairo index f5ba8f3f..a6c836df 100644 --- a/onchain/cairo/src/afk_id/nameservice.cairo +++ b/onchain/cairo/src/afk_id/nameservice.cairo @@ -94,6 +94,20 @@ pub mod Nameservice { pub is_claimed: bool } + #[derive(Drop, Debug, Serde, Copy, starknet::Store, PartialEq)] + pub struct Auction { + pub minimal_price: u256, + pub is_accepted_price_reached: bool, + pub highest_bid: u256, + pub highest_bidder: ContractAddress + } + + #[derive(Drop, Debug, Serde, Copy, starknet::Store, PartialEq)] + struct Order { + bidder: ContractAddress, + amount: u256, + } + #[storage] struct Storage { usernames: Map::, @@ -101,6 +115,9 @@ pub mod Nameservice { usernames_claimed_by_user: Map>, subscription_expiry: Map::, username_storage: Map::, + auctions: Map::, + orders: Map<(felt252, u64), Order>, + order_count: Map, subscription_price: u256, token_quote: ContractAddress, is_payment_enabled: bool, @@ -120,6 +137,8 @@ pub mod Nameservice { erc20: ERC20Component::Storage, } + + #[event] #[derive(Drop, starknet::Event)] pub enum Event { @@ -324,11 +343,58 @@ pub mod Nameservice { username: felt252, minimal_price: u256, is_accepted_price_reached: bool - ) {} + ) { + let caller_address = get_caller_address(); + let username_address = self.usernames.read(username); + assert(username_address == caller_address, 'Username not callers'); + + let existing_auction = self.auctions.read(username); + assert(existing_auction.minimal_price == 0, 'Auction does not exist'); + + // Create a new auction + let new_auction = Auction { + minimal_price: minimal_price, + is_accepted_price_reached: is_accepted_price_reached, + highest_bid: 0, + highest_bidder: contract_address_const::<0>(), + }; + + // Store the auction + self.auctions.write(username, new_auction); + } // TODO - fn place_order(ref self: ContractState, username: felt252, amount: u256) {} + fn place_order(ref self: ContractState, username: felt252, amount: u256) { + let auction = self.auctions.read(username); + assert(auction.minimal_price > 0, 'Auction does not exist'); + + assert(amount >= auction.minimal_price, 'Bid too low'); + + // Create a new order + let bidder = get_caller_address(); + + let order_id = self.order_count.read(username) + 1; + let new_order = Order { bidder: bidder, amount: amount }; + + // Store the order + self.orders.write((username, order_id), new_order); + self.order_count.write(username, order_id); + + // Update auction if this is the highest bid + if amount > auction.highest_bid { + let mut updated_auction = auction; + updated_auction.highest_bid = amount; + updated_auction.highest_bidder = bidder; + self.auctions.write(username, updated_auction); + } + } + + fn get_auction(self: @ContractState, username: felt252) -> Auction { + // Read the auction from storage + let auction = self.auctions.read(username); + auction + } // TODO fn accept_order(ref self: ContractState, username: felt252, id: u64) {} @@ -413,6 +479,9 @@ pub mod Nameservice { fn get_subscription_expiry(self: @ContractState, address: ContractAddress) -> u64 { self.subscription_expiry.read(address) } + + + fn withdraw_fees(ref self: ContractState, amount: u256) { self.accesscontrol.assert_only_role(ADMIN_ROLE); let token = IERC20Dispatcher { contract_address: self.token_quote.read() }; diff --git a/onchain/cairo/src/interfaces/nameservice.cairo b/onchain/cairo/src/interfaces/nameservice.cairo index e9a8b2d1..995e312f 100644 --- a/onchain/cairo/src/interfaces/nameservice.cairo +++ b/onchain/cairo/src/interfaces/nameservice.cairo @@ -1,4 +1,5 @@ use starknet::ContractAddress; +use afk::afk_id::nameservice::Nameservice::{Auction}; #[starknet::interface] pub trait INameservice { @@ -27,4 +28,5 @@ pub trait INameservice { fn update_subscription_price(ref self: TContractState, new_price: u256); fn set_is_payment_enabled(ref self: TContractState, new_status: bool) -> bool; fn get_is_payment_enabled(self: @TContractState) -> bool; + fn get_auction(self: @TContractState, username: felt252) -> Auction; } diff --git a/onchain/cairo/src/lib.cairo b/onchain/cairo/src/lib.cairo index 6e5f05b4..12337dd7 100644 --- a/onchain/cairo/src/lib.cairo +++ b/onchain/cairo/src/lib.cairo @@ -9,7 +9,6 @@ pub mod sha256; pub mod social; pub mod utils; pub mod launchpad { - pub mod calcul; pub mod errors; pub mod helpers; pub mod launchpad; @@ -107,7 +106,6 @@ pub mod tests { // pub mod identity_tests; pub mod keys_tests; pub mod launchpad_tests; - pub mod liquidity_tests; pub mod nameservice_tests; pub mod quest_factory_test; pub mod tap_tests; diff --git a/onchain/cairo/src/tests/nameservice_tests.cairo b/onchain/cairo/src/tests/nameservice_tests.cairo index f60b76b0..897d061d 100644 --- a/onchain/cairo/src/tests/nameservice_tests.cairo +++ b/onchain/cairo/src/tests/nameservice_tests.cairo @@ -15,6 +15,12 @@ mod nameservice_tests { fn CALLER() -> ContractAddress { starknet::contract_address_const::<2>() } + fn NEW_CALLER() -> ContractAddress { + starknet::contract_address_const::<3>() + } + fn THIRD_CALLER() -> ContractAddress { + starknet::contract_address_const::<4>() + } const ADMIN_ROLE: felt252 = selector!("ADMIN_ROLE"); const YEAR_IN_SECONDS: u64 = 31536000_u64; const PAYMENT_AMOUNT: felt252 = 10; @@ -251,4 +257,103 @@ mod nameservice_tests { assert(subscription_price == 10_u256, 'Price is not correct'); assert(new_subscription_price == 30_u256, 'Price is not correct'); } + + #[test] + fn test_create_auction_for_username() { + let (nameservice_dispatcher, payment_token_dispatcher, payment_token_mintable_dispatcher) = + setup(); + let MINTER_ROLE: felt252 = selector!("MINTER_ROLE"); + + start_cheat_caller_address(payment_token_mintable_dispatcher.contract_address, ADMIN()); + payment_token_mintable_dispatcher + .set_role(recipient: ADMIN(), role: MINTER_ROLE, is_enable: true); + payment_token_mintable_dispatcher.mint(CALLER(), 20_u256); + stop_cheat_caller_address(payment_token_mintable_dispatcher.contract_address); + + start_cheat_caller_address(payment_token_dispatcher.contract_address, CALLER()); + payment_token_dispatcher.approve(nameservice_dispatcher.contract_address, 20_u256); + stop_cheat_caller_address(payment_token_dispatcher.contract_address); + + start_cheat_caller_address(nameservice_dispatcher.contract_address, ADMIN()); + nameservice_dispatcher.set_is_payment_enabled(true); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + let username = selector!("test"); + start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); + nameservice_dispatcher.claim_username(username); + nameservice_dispatcher.create_auction_for_username(username, 100_u256, false); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + let existing_auction = nameservice_dispatcher.get_auction(username); + assert(existing_auction.minimal_price == 100, 'Minimal price not correct'); + assert(existing_auction.is_accepted_price_reached == false, 'price not correct'); + assert(existing_auction.highest_bid == 0, 'highest_bid not correct'); + assert(existing_auction.highest_bidder == starknet::contract_address_const::<0>(), 'highest_bidder not correct'); + } + + #[test] + #[should_panic(expected: 'Username not callers')] + fn test_create_auction_for_username_fail() { + let (nameservice_dispatcher, payment_token_dispatcher, payment_token_mintable_dispatcher) = + setup(); + let MINTER_ROLE: felt252 = selector!("MINTER_ROLE"); + + start_cheat_caller_address(payment_token_mintable_dispatcher.contract_address, ADMIN()); + payment_token_mintable_dispatcher + .set_role(recipient: ADMIN(), role: MINTER_ROLE, is_enable: true); + payment_token_mintable_dispatcher.mint(CALLER(), 20_u256); + stop_cheat_caller_address(payment_token_mintable_dispatcher.contract_address); + + start_cheat_caller_address(payment_token_dispatcher.contract_address, CALLER()); + payment_token_dispatcher.approve(nameservice_dispatcher.contract_address, 20_u256); + stop_cheat_caller_address(payment_token_dispatcher.contract_address); + + start_cheat_caller_address(nameservice_dispatcher.contract_address, ADMIN()); + nameservice_dispatcher.set_is_payment_enabled(true); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + let username = selector!("test"); + start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); + nameservice_dispatcher.create_auction_for_username(username, 100_u256, false); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + } + + #[test] + fn test_place_order() { + let (nameservice_dispatcher, payment_token_dispatcher, payment_token_mintable_dispatcher) = + setup(); + let MINTER_ROLE: felt252 = selector!("MINTER_ROLE"); + + start_cheat_caller_address(payment_token_mintable_dispatcher.contract_address, ADMIN()); + payment_token_mintable_dispatcher + .set_role(recipient: ADMIN(), role: MINTER_ROLE, is_enable: true); + payment_token_mintable_dispatcher.mint(CALLER(), 20_u256); + stop_cheat_caller_address(payment_token_mintable_dispatcher.contract_address); + + start_cheat_caller_address(payment_token_dispatcher.contract_address, CALLER()); + payment_token_dispatcher.approve(nameservice_dispatcher.contract_address, 20_u256); + stop_cheat_caller_address(payment_token_dispatcher.contract_address); + + start_cheat_caller_address(nameservice_dispatcher.contract_address, ADMIN()); + nameservice_dispatcher.set_is_payment_enabled(true); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + let username = selector!("test"); + start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); + nameservice_dispatcher.claim_username(username); + nameservice_dispatcher.create_auction_for_username(username, 100_u256, false); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + start_cheat_caller_address(nameservice_dispatcher.contract_address, NEW_CALLER()); + nameservice_dispatcher.place_order(username, 200_u256); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + start_cheat_caller_address(nameservice_dispatcher.contract_address, THIRD_CALLER()); + nameservice_dispatcher.place_order(username, 150_u256); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + let existing_auction = nameservice_dispatcher.get_auction(username); + assert(existing_auction.highest_bid == 200, 'highest_bid not correct'); + assert(existing_auction.highest_bidder == NEW_CALLER(), 'highest_bidder not correct'); + } } From c3d6b78075c7e5d8173e1bb9555c8cb79140ed4c Mon Sep 17 00:00:00 2001 From: Hakeem Kazeem Date: Wed, 27 Nov 2024 08:00:36 +0100 Subject: [PATCH 2/9] place order and test --- onchain/cairo/src/afk_id/nameservice.cairo | 55 +- onchain/cairo/src/launchpad/launchpad.cairo | 3990 ++++++++--------- onchain/cairo/src/tests/launchpad_tests.cairo | 3820 ++++++++-------- .../cairo/src/tests/nameservice_tests.cairo | 158 +- 4 files changed, 4092 insertions(+), 3931 deletions(-) diff --git a/onchain/cairo/src/afk_id/nameservice.cairo b/onchain/cairo/src/afk_id/nameservice.cairo index a6c836df..ff8e877a 100644 --- a/onchain/cairo/src/afk_id/nameservice.cairo +++ b/onchain/cairo/src/afk_id/nameservice.cairo @@ -116,8 +116,9 @@ pub mod Nameservice { subscription_expiry: Map::, username_storage: Map::, auctions: Map::, - orders: Map<(felt252, u64), Order>, + orders: Map, order_count: Map, + order_return: Map::, subscription_price: u256, token_quote: ContractAddress, is_payment_enabled: bool, @@ -345,7 +346,8 @@ pub mod Nameservice { is_accepted_price_reached: bool ) { let caller_address = get_caller_address(); - let username_address = self.usernames.read(username); + let username_address = self.get_username_address(username); + assert(username_address == caller_address, 'Username not callers'); let existing_auction = self.auctions.read(username); @@ -368,38 +370,55 @@ pub mod Nameservice { let auction = self.auctions.read(username); assert(auction.minimal_price > 0, 'Auction does not exist'); - - assert(amount >= auction.minimal_price, 'Bid too low'); + assert(amount > auction.highest_bid, 'Bid too low'); // Create a new order let bidder = get_caller_address(); + let quote_token = self.token_quote.read(); + + // check if new bidder alredy has an outbidded amount (still in the contract) + let bidder_amount = self.order_return.read(bidder); + self.order_return.entry(bidder).write(0); + let new_amount = amount - bidder_amount; + + if self.is_payment_enabled.read() { + let payment_token = IERC20Dispatcher { contract_address: quote_token }; + payment_token.transfer_from(bidder, get_contract_address(), new_amount); + } let order_id = self.order_count.read(username) + 1; - let new_order = Order { bidder: bidder, amount: amount }; + let new_order = Order { bidder: bidder, amount: new_amount }; + + let old_order = self.orders.read(username); // Store the order - self.orders.write((username, order_id), new_order); + self.orders.write(username, new_order); self.order_count.write(username, order_id); - // Update auction if this is the highest bid - if amount > auction.highest_bid { - let mut updated_auction = auction; - updated_auction.highest_bid = amount; - updated_auction.highest_bidder = bidder; - self.auctions.write(username, updated_auction); - } + let order_return_amount = self.order_return.read(old_order.bidder); + println!(" order_return_amount: {:?}", order_return_amount); + self.order_return.entry(old_order.bidder).write((order_return_amount + old_order.amount)); + + // Update auction if this is the highest bid + let mut updated_auction = auction; + updated_auction.highest_bid = amount; + updated_auction.highest_bidder = bidder; + self.auctions.write(username, updated_auction); } + + // TODO + fn accept_order(ref self: ContractState, username: felt252, id: u64) {} + + // TODO + fn cancel_order(ref self: ContractState, username: felt252, id: u64) { + } + fn get_auction(self: @ContractState, username: felt252) -> Auction { // Read the auction from storage let auction = self.auctions.read(username); auction } - // TODO - fn accept_order(ref self: ContractState, username: felt252, id: u64) {} - - // TODO - fn cancel_order(ref self: ContractState, username: felt252, id: u64) {} // TODO fn renew_subscription(ref self: ContractState) { diff --git a/onchain/cairo/src/launchpad/launchpad.cairo b/onchain/cairo/src/launchpad/launchpad.cairo index f35f8ba9..57531939 100644 --- a/onchain/cairo/src/launchpad/launchpad.cairo +++ b/onchain/cairo/src/launchpad/launchpad.cairo @@ -1,1995 +1,1995 @@ -use afk::types::jediswap_types::{MintParams}; -use afk::types::launchpad_types::{ - MINTER_ROLE, ADMIN_ROLE, StoredName, BuyToken, SellToken, CreateToken, LaunchUpdated, - TokenQuoteBuyCoin, TokenLaunch, SharesTokenUser, BondingType, Token, CreateLaunch, - SetJediswapNFTRouterV2, SetJediswapV2Factory, SupportedExchanges, LiquidityCreated, - LiquidityCanBeAdded, MetadataLaunch, TokenClaimed, MetadataCoinAdded, EkuboPoolParameters, - LaunchParameters, EkuboLP, CallbackData, EkuboLaunchParameters, LaunchCallback, LiquidityType, - EkuboLiquidityParameters, LiquidityParameters -}; -use starknet::ClassHash; -use starknet::ContractAddress; - -#[starknet::interface] -pub trait ILaunchpadMarketplace { - // User call - fn create_token( - ref self: TContractState, - recipient: ContractAddress, - symbol: felt252, - name: felt252, - initial_supply: u256, - contract_address_salt: felt252, - is_unruggable: bool - ) -> ContractAddress; - - fn create_and_launch_token( - ref self: TContractState, - symbol: felt252, - name: felt252, - initial_supply: u256, - contract_address_salt: felt252, - is_unruggable: bool - ) -> ContractAddress; - fn launch_token(ref self: TContractState, coin_address: ContractAddress); - fn launch_liquidity(ref self: TContractState, coin_address: ContractAddress); - // fn buy_coin(ref self: TContractState, coin_address: ContractAddress, amount: u256); - fn buy_coin_by_quote_amount( - ref self: TContractState, coin_address: ContractAddress, quote_amount: u256, - // ekubo_pool_params: Option, - ); - fn sell_coin(ref self: TContractState, coin_address: ContractAddress, quote_amount: u256); - - fn claim_coin_buy(ref self: TContractState, coin_address: ContractAddress, amount: u256); - fn add_metadata( - ref self: TContractState, coin_address: ContractAddress, metadata: MetadataLaunch - ); - - // Views - fn get_threshold_liquidity(self: @TContractState) -> u256; - fn get_default_token(self: @TContractState,) -> TokenQuoteBuyCoin; - - // Main function to calculate amount - fn get_amount_by_type_of_coin_or_quote( - self: @TContractState, - coin_address: ContractAddress, - amount: u256, - is_decreased: bool, - is_quote_amount: bool - ) -> u256; - fn get_coin_amount_by_quote_amount( - self: @TContractState, coin_address: ContractAddress, quote_amount: u256, is_decreased: bool - ) -> u256; - - // fn get_quote_paid_by_amount_coin( - // self: @TContractState, coin_address: ContractAddress, quote_amount: u256, is_decreased: - // bool - // ) -> u256; - - fn get_coin_launch(self: @TContractState, key_user: ContractAddress,) -> TokenLaunch; - fn get_share_key_of_user( - self: @TContractState, owner: ContractAddress, key_user: ContractAddress, - ) -> SharesTokenUser; - fn get_all_launch(self: @TContractState) -> Span; - - fn get_all_coins(self: @TContractState) -> Span; - - // Admins - fn set_token(ref self: TContractState, token_quote: TokenQuoteBuyCoin); - fn set_protocol_fee_percent(ref self: TContractState, protocol_fee_percent: u256); - fn set_creator_fee_percent(ref self: TContractState, creator_fee_percent: u256); - fn set_dollar_paid_coin_creation(ref self: TContractState, dollar_price: u256); - fn set_dollar_paid_launch_creation(ref self: TContractState, dollar_price: u256); - fn set_dollar_paid_finish_percentage(ref self: TContractState, bps: u256); - fn set_class_hash(ref self: TContractState, class_hash: ClassHash); - fn set_protocol_fee_destination( - ref self: TContractState, protocol_fee_destination: ContractAddress - ); - fn set_threshold_liquidity(ref self: TContractState, threshold_liquidity: u256); - fn set_address_jediswap_factory_v2( - ref self: TContractState, address_jediswap_factory_v2: ContractAddress - ); - fn set_address_jediswap_nft_router_v2( - ref self: TContractState, address_jediswap_nft_router_v2: ContractAddress - ); - fn set_address_ekubo_factory(ref self: TContractState, address_ekubo_factory: ContractAddress); - fn set_address_ekubo_router(ref self: TContractState, address_ekubo_router: ContractAddress); - fn set_exchanges_address( - ref self: TContractState, exchanges: Span<(SupportedExchanges, ContractAddress)> - ); - - //TODO - fn add_liquidity_jediswap(ref self: TContractState, coin_address: ContractAddress,); - fn add_liquidity_unrug( - ref self: TContractState, - coin_address: ContractAddress, - launch_params: LaunchParameters, - ekubo_pool_params: EkuboPoolParameters - ) -> (u64, EkuboLP); - - fn add_liquidity_unrug_lp( - ref self: TContractState, - coin_address: ContractAddress, - quote_address: ContractAddress, - lp_supply: u256, - launch_params: LaunchParameters, - ekubo_pool_params: EkuboPoolParameters - ) -> (u64, EkuboLP); - - fn add_liquidity_ekubo( - ref self: TContractState, coin_address: ContractAddress, - // params: EkuboLaunchParameters - ) -> (u64, EkuboLP); - // ) -> Span; - - fn create_unrug_token( - ref self: TContractState, - owner: ContractAddress, - name: felt252, - symbol: felt252, - initial_supply: u256, - contract_address_salt: felt252, - is_launch_bonding_now: bool - ) -> ContractAddress; -} - -#[starknet::contract] -pub mod LaunchpadMarketplace { - use afk::interfaces::factory::{IFactory, IFactoryDispatcher, IFactoryDispatcherTrait}; - use afk::interfaces::jediswap::{ - IJediswapFactoryV2, IJediswapFactoryV2Dispatcher, IJediswapFactoryV2DispatcherTrait, - IJediswapNFTRouterV2, IJediswapNFTRouterV2Dispatcher, IJediswapNFTRouterV2DispatcherTrait, - }; - use afk::launchpad::calcul::{ - calculate_starting_price_launch, calculate_slope, calculate_pricing, - get_amount_by_type_of_coin_or_quote, get_coin_amount_by_quote_amount - }; - use afk::launchpad::errors; - // use afk::launchpad::helpers::{distribute_team_alloc, check_common_launch_parameters }; - use afk::launchpad::helpers::{distribute_team_alloc, check_common_launch_parameters}; - use afk::launchpad::math::PercentageMath; - use afk::launchpad::utils::{ - sort_tokens, get_initial_tick_from_starting_price, get_next_tick_bounds, unique_count, - calculate_aligned_bound_mag - }; - use afk::tokens::erc20::{ERC20, IERC20Dispatcher, IERC20DispatcherTrait}; - use afk::tokens::memecoin::{IMemecoinDispatcher, IMemecoinDispatcherTrait}; - use afk::utils::{sqrt}; - use core::num::traits::Zero; - use ekubo::components::clear::{IClearDispatcher, IClearDispatcherTrait}; - - use ekubo::components::shared_locker::{call_core_with_callback, consume_callback_data}; - use ekubo::interfaces::core::{ICoreDispatcher, ICoreDispatcherTrait, ILocker}; - use ekubo::interfaces::erc20::{ - IERC20Dispatcher as EKIERC20Dispatcher, IERC20DispatcherTrait as EKIERC20DispatcherTrait - }; - use ekubo::interfaces::positions::{IPositions, IPositionsDispatcher, IPositionsDispatcherTrait}; - use ekubo::interfaces::router::{IRouterDispatcher, IRouterDispatcherTrait}; - use ekubo::interfaces::token_registry::{ - ITokenRegistryDispatcher, ITokenRegistryDispatcherTrait, - }; - use ekubo::types::bounds::{Bounds}; - use ekubo::types::keys::PoolKey; - use ekubo::types::{i129::i129}; - - use openzeppelin::access::accesscontrol::{AccessControlComponent}; - use openzeppelin::introspection::src5::SRC5Component; - use starknet::storage::{ - StoragePointerReadAccess, StoragePointerWriteAccess, StoragePathEntry, Map - }; - use starknet::syscalls::deploy_syscall; - use starknet::{ - ContractAddress, get_caller_address, storage_access::StorageBaseAddress, - contract_address_const, get_block_timestamp, get_contract_address, ClassHash - }; - use super::{ - StoredName, BuyToken, SellToken, CreateToken, LaunchUpdated, SharesTokenUser, MINTER_ROLE, - ADMIN_ROLE, BondingType, Token, TokenLaunch, TokenQuoteBuyCoin, CreateLaunch, - SetJediswapNFTRouterV2, SetJediswapV2Factory, SupportedExchanges, MintParams, - LiquidityCreated, LiquidityCanBeAdded, MetadataLaunch, TokenClaimed, MetadataCoinAdded, - EkuboPoolParameters, LaunchParameters, EkuboLP, LiquidityType, CallbackData, - EkuboLaunchParameters, LaunchCallback, EkuboLiquidityParameters, LiquidityParameters - }; - - - const MAX_SUPPLY: u256 = 100_000_000; - const INITIAL_SUPPLY: u256 = MAX_SUPPLY / 5; - const MAX_STEPS_LOOP: u256 = 100; - // Total supply / LIQUIDITY_RATIO - // Get the 20% of Bonding curve going to Liquidity - // Liquidity can be lock to Unrug - const LIQUIDITY_RATIO: u256 = 5; // Divid by 5 the total supply. - // TODO add with a enabled pay boolean to be free at some point - const PAY_TO_LAUNCH: u256 = 1; // amount in the coin used - const LIQUIDITY_PERCENTAGE: u256 = 2000; //20% - const MIN_FEE_PROTOCOL: u256 = 10; //0.1% - const MAX_FEE_PROTOCOL: u256 = 1000; //10% - const MID_FEE_PROTOCOL: u256 = 100; //1% - - const MIN_FEE_CREATOR: u256 = 100; //1% - const MID_FEE_CREATOR: u256 = 1000; //10% - const MAX_FEE_CREATOR: u256 = 5000; //50% - - const BPS: u256 = 10_000; // 100% = 10_000 bps - const SCALE_FACTOR: u256 = - 100_000_000_000_000_000; // Scale factor decimals place for price division and others stuff - - // Unrug params - - // CHANGE it - /// The maximum percentage of the total supply that can be allocated to the team. - /// This is to prevent the team from having too much control over the supply. - const MAX_SUPPLY_PERCENTAGE_TEAM_ALLOCATION: u16 = 1_000; // 10% - - /// The maximum number of holders one can specify when launching. - /// This is to prevent the contract from being is_launched with a large number of holders. - /// Once reached, transfers are disabled until the memecoin is is_launched. - const MAX_HOLDERS_LAUNCH: u8 = 10; - - component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent); - component!(path: SRC5Component, storage: src5, event: SRC5Event); - - // AccessControl - #[abi(embed_v0)] - impl AccessControlImpl = - AccessControlComponent::AccessControlImpl; - impl AccessControlInternalImpl = AccessControlComponent::InternalImpl; - - // SRC5 - #[abi(embed_v0)] - impl SRC5Impl = SRC5Component::SRC5Impl; - - #[storage] - struct Storage { - // Admin & others contract - coin_class_hash: ClassHash, - quote_tokens: Map::, - exchange_configs: Map, - quote_token: ContractAddress, - protocol_fee_destination: ContractAddress, - address_jediswap_factory_v2: ContractAddress, - address_jediswap_nft_router_v2: ContractAddress, - address_ekubo_factory: ContractAddress, - address_ekubo_router: ContractAddress, - // User states - token_created: Map::, - launched_coins: Map::, - metadata_coins: Map::, - shares_by_users: Map::<(ContractAddress, ContractAddress), SharesTokenUser>, - bonding_type: Map::, - array_launched_coins: Map::, - array_coins: Map::, - tokens_created: Map::, - launch_created: Map::, - // Parameters - is_tokens_buy_enable: Map::, - default_token: TokenQuoteBuyCoin, - dollar_price_launch_pool: u256, - dollar_price_create_token: u256, - dollar_price_percentage: u256, - starting_price: u256, - threshold_liquidity: u256, - threshold_market_cap: u256, - liquidity_raised_amount_in_dollar: u256, - protocol_fee_percent: u256, - creator_fee_percent: u256, - is_fees_protocol: bool, - step_increase_linear: u256, - is_custom_launch_enable: bool, - is_custom_token_enable: bool, - is_paid_launch_enable: bool, - is_create_token_paid: bool, - // Stats - total_keys: u64, - total_token: u64, - total_launch: u64, - total_shares_keys: u64, - // External contract - factory_address: ContractAddress, - ekubo_registry: ContractAddress, - core: ContractAddress, - positions: ContractAddress, - ekubo_exchange_address: ContractAddress, - #[substorage(v0)] - accesscontrol: AccessControlComponent::Storage, - #[substorage(v0)] - src5: SRC5Component::Storage, - } - - #[event] - #[derive(Drop, starknet::Event)] - pub enum Event { - StoredName: StoredName, - BuyToken: BuyToken, - SellToken: SellToken, - CreateToken: CreateToken, - LaunchUpdated: LaunchUpdated, - CreateLaunch: CreateLaunch, - SetJediswapV2Factory: SetJediswapV2Factory, - SetJediswapNFTRouterV2: SetJediswapNFTRouterV2, - LiquidityCreated: LiquidityCreated, - LiquidityCanBeAdded: LiquidityCanBeAdded, - TokenClaimed: TokenClaimed, - MetadataCoinAdded: MetadataCoinAdded, - #[flat] - AccessControlEvent: AccessControlComponent::Event, - #[flat] - SRC5Event: SRC5Component::Event, - } - - #[constructor] - fn constructor( - ref self: ContractState, - admin: ContractAddress, - starting_price: u256, - token_address: ContractAddress, - step_increase_linear: u256, - coin_class_hash: ClassHash, - threshold_liquidity: u256, - threshold_market_cap: u256, - factory_address: ContractAddress, - ekubo_registry: ContractAddress, - core: ContractAddress, - positions: ContractAddress, - ekubo_exchange_address: ContractAddress - ) { - self.coin_class_hash.write(coin_class_hash); - // AccessControl-related initialization - self.accesscontrol.initializer(); - self.accesscontrol._grant_role(MINTER_ROLE, admin); - self.accesscontrol._grant_role(ADMIN_ROLE, admin); - - let init_token = TokenQuoteBuyCoin { - token_address: token_address, - starting_price, - price: starting_price, - is_enable: true, - step_increase_linear - }; - self.is_custom_launch_enable.write(false); - self.is_custom_token_enable.write(false); - self.default_token.write(init_token.clone()); - self.starting_price.write(init_token.starting_price); - - self.threshold_liquidity.write(threshold_liquidity); - self.threshold_market_cap.write(threshold_market_cap); - self.protocol_fee_destination.write(admin); - self.step_increase_linear.write(step_increase_linear); - self.total_keys.write(0); - self.total_token.write(0); - self.total_launch.write(0); - self.protocol_fee_percent.write(MID_FEE_PROTOCOL); - self.creator_fee_percent.write(MIN_FEE_CREATOR); - self.factory_address.write(factory_address); - // self.ekubo_registry.write(ekubo_registry); - self.core.write(core); - self.positions.write(positions); - self.ekubo_exchange_address.write(ekubo_exchange_address); - } - - // Public functions inside an impl block - #[abi(embed_v0)] - impl LaunchpadMarketplace of super::ILaunchpadMarketplace { - // ADMIN - - fn set_token(ref self: ContractState, token_quote: TokenQuoteBuyCoin) { - self.accesscontrol.assert_only_role(ADMIN_ROLE); - self.is_tokens_buy_enable.entry(token_quote.token_address).write(token_quote); - } - - fn set_protocol_fee_percent(ref self: ContractState, protocol_fee_percent: u256) { - assert(protocol_fee_percent < MAX_FEE_PROTOCOL, 'protocol_fee_too_high'); - assert(protocol_fee_percent > MIN_FEE_PROTOCOL, 'protocol_fee_too_low'); - - self.accesscontrol.assert_only_role(ADMIN_ROLE); - self.protocol_fee_percent.write(protocol_fee_percent); - } - - fn set_protocol_fee_destination( - ref self: ContractState, protocol_fee_destination: ContractAddress - ) { - self.accesscontrol.assert_only_role(ADMIN_ROLE); - self.protocol_fee_destination.write(protocol_fee_destination); - } - - fn set_creator_fee_percent(ref self: ContractState, creator_fee_percent: u256) { - self.accesscontrol.assert_only_role(ADMIN_ROLE); - assert(creator_fee_percent < MAX_FEE_CREATOR, 'creator_fee_too_high'); - assert(creator_fee_percent > MIN_FEE_CREATOR, 'creator_fee_too_low'); - self.creator_fee_percent.write(creator_fee_percent); - } - - fn set_dollar_paid_coin_creation(ref self: ContractState, dollar_price: u256) { - self.accesscontrol.assert_only_role(ADMIN_ROLE); - self.dollar_price_create_token.write(dollar_price); - } - - fn set_dollar_paid_launch_creation(ref self: ContractState, dollar_price: u256) { - self.accesscontrol.assert_only_role(ADMIN_ROLE); - self.dollar_price_launch_pool.write(dollar_price); - } - - fn set_dollar_paid_finish_percentage(ref self: ContractState, bps: u256) { - self.accesscontrol.assert_only_role(ADMIN_ROLE); - self.dollar_price_percentage.write(bps); - } - - // Set threshold liquidity - fn set_threshold_liquidity(ref self: ContractState, threshold_liquidity: u256) { - self.accesscontrol.assert_only_role(ADMIN_ROLE); - self.threshold_liquidity.write(threshold_liquidity); - } - - // Jediwswap factory address - fn set_address_jediswap_factory_v2( - ref self: ContractState, address_jediswap_factory_v2: ContractAddress - ) { - self.accesscontrol.assert_only_role(ADMIN_ROLE); - // self.ownable.assert_only_owner(); - self.address_jediswap_factory_v2.write(address_jediswap_factory_v2); - self - .emit( - SetJediswapV2Factory { - address_jediswap_factory_v2: address_jediswap_factory_v2 - } - ); - } - - fn set_address_jediswap_nft_router_v2( - ref self: ContractState, address_jediswap_nft_router_v2: ContractAddress - ) { - self.accesscontrol.assert_only_role(ADMIN_ROLE); - self.address_jediswap_nft_router_v2.write(address_jediswap_nft_router_v2); - self - .emit( - SetJediswapNFTRouterV2 { - address_jediswap_nft_router_v2: address_jediswap_nft_router_v2 - } - ); - } - - fn set_address_ekubo_factory( - ref self: ContractState, address_ekubo_factory: ContractAddress - ) { - self.accesscontrol.assert_only_role(ADMIN_ROLE); - self.address_ekubo_factory.write(address_ekubo_factory); - // Optionally emit an event - } - - fn set_address_ekubo_router( - ref self: ContractState, address_ekubo_router: ContractAddress - ) { - self.accesscontrol.assert_only_role(ADMIN_ROLE); - self.address_ekubo_router.write(address_ekubo_router); - // Optionally emit an event - } - - fn set_exchanges_address( - ref self: ContractState, exchanges: Span<(SupportedExchanges, ContractAddress)> - ) { - self.accesscontrol.assert_only_role(ADMIN_ROLE); - let mut dex = exchanges; - // Add Exchanges configurations - loop { - match dex.pop_front() { - Option::Some((exchange, address)) => self - .exchange_configs - .entry(*exchange) - .write(*address), - Option::None => { break; } - } - }; - } - - - fn set_class_hash(ref self: ContractState, class_hash: ClassHash) { - self.accesscontrol.assert_only_role(ADMIN_ROLE); - self.coin_class_hash.write(class_hash); - } - // User call - - // Create keys for an user - fn create_token( - ref self: ContractState, - recipient: ContractAddress, - symbol: felt252, - name: felt252, - initial_supply: u256, - contract_address_salt: felt252, - is_unruggable: bool - ) -> ContractAddress { - let caller = get_caller_address(); - let token_address = self - ._create_token( - recipient, - caller, - symbol, - name, - initial_supply, - contract_address_salt, - is_unruggable - ); - - token_address - } - - // Creat coin and launch - // recipient, caller, symbol, name, initial_supply, contract_address_salt - fn create_and_launch_token( - ref self: ContractState, - symbol: felt252, - name: felt252, - initial_supply: u256, - contract_address_salt: felt252, - is_unruggable: bool - ) -> ContractAddress { - let contract_address = get_contract_address(); - let caller = get_caller_address(); - let token_address = self - ._create_token( - contract_address, - caller, - symbol, - name, - initial_supply, - contract_address_salt, - is_unruggable - ); - let contract_address = get_contract_address(); - self._launch_token(token_address, caller, contract_address, false); - token_address - } - - // Launch coin to pool bonding curve - fn launch_token(ref self: ContractState, coin_address: ContractAddress) { - let caller = get_caller_address(); - let contract_address = get_contract_address(); - - let token = self.token_created.read(coin_address); - let is_unruggable = token.is_unruggable; - self._launch_token(coin_address, caller, contract_address, is_unruggable); - } - - // Buy coin by quote amount - // Get amount of coin receive based on token IN - fn buy_coin_by_quote_amount( - ref self: ContractState, coin_address: ContractAddress, quote_amount: u256, - // ekubo_pool_params: Option - ) { - // assert!(quote_amount > 0, "amount == 0"); - let caller = get_caller_address(); - let old_launch = self.launched_coins.read(coin_address); - assert!(!old_launch.owner.is_zero(), "coin not found"); - let memecoin = IERC20Dispatcher { contract_address: coin_address }; - let mut pool_coin = old_launch.clone(); - let total_supply_memecoin = memecoin.total_supply(); - // let threshold_liquidity = self.threshold_liquidity.read(); - let threshold_liquidity = pool_coin.threshold_liquidity.clone(); - - //new liquidity after purchase - let new_liquidity = pool_coin.liquidity_raised + quote_amount; - - //assertion - assert(new_liquidity <= threshold_liquidity, 'threshold liquidity exceeded'); - - // TODO erc20 token transfer - let token_quote = old_launch.token_quote.clone(); - let quote_token_address = token_quote.token_address.clone(); - let erc20 = IERC20Dispatcher { contract_address: quote_token_address }; - let protocol_fee_percent = self.protocol_fee_percent.read(); - - // IF AMOUNT COIN TO HAVE => GET AMOUNT QUOTE TO PAID - let mut total_price = quote_amount.clone(); - let old_price = pool_coin.price.clone(); - let mut amount_protocol_fee: u256 = total_price * protocol_fee_percent / BPS; - let mut remain_liquidity = total_price - amount_protocol_fee; - // let mut amount = 0; - // Pay with quote token - // Transfer quote & coin - // TOdo fix issue price - let mut amount = get_amount_by_type_of_coin_or_quote( - pool_coin.clone(), coin_address.clone(), remain_liquidity.clone(), false, true - ); - // remain_liquidity = total_price - amount_protocol_fee; - // TODO check available to buy - - // println!("amount receive {:?}", amount); - - assert(amount <= pool_coin.available_supply, 'no available supply'); - - erc20 - .transfer_from( - get_caller_address(), self.protocol_fee_destination.read(), amount_protocol_fee - ); - // println!("remain_liquidity {:?}", remain_liquidity); - erc20.transfer_from(get_caller_address(), get_contract_address(), remain_liquidity); - // In case the user want to buy more than the threshold - // Give the available supply - // if total_price + old_launch.liquidity_raised.clone() > threshold_liquidity { - // total_price = threshold_liquidity - old_launch.liquidity_raised.clone(); - // amount = pool_coin.available_supply; - - // amount_protocol_fee = total_price * protocol_fee_percent / BPS; - // // remain_liquidity = total_price - amount_protocol_fee; - // remain_liquidity = total_price; - // erc20 - // .transfer_from( - // get_caller_address(), - // self.protocol_fee_destination.read(), - // amount_protocol_fee - // ); - // // println!("remain_liquidity {:?}", remain_liquidity); - // erc20.transfer_from(get_caller_address(), get_contract_address(), - // remain_liquidity); - // } else { - // amount = self - // ._get_amount_by_type_of_coin_or_quote(coin_address, total_price, false, - // true); - // // remain_liquidity = total_price - amount_protocol_fee; - - // erc20 - // .transfer_from( - // get_caller_address(), - // self.protocol_fee_destination.read(), - // amount_protocol_fee - // ); - // // println!("remain_liquidity {:?}", remain_liquidity); - // erc20.transfer_from(get_caller_address(), get_contract_address(), - // remain_liquidity); - // } - - // Assertion: Amount Received Validation - // Optionally, re-calculate the quote amount based on the amount to ensure consistency - // println!("total_price {:?}", total_price); - // Change the Stats of pool: - // Liquidity raised - // Available supply - // Token holded - - pool_coin.liquidity_raised += remain_liquidity; - pool_coin.total_token_holded += amount; - pool_coin.price = total_price; - - if amount >= pool_coin.available_supply { - pool_coin.available_supply = 0; - } else { - pool_coin.available_supply -= amount; - } - - // Update share and coin stats for an user - let mut old_share = self.shares_by_users.read((get_caller_address(), coin_address)); - - let mut share_user = old_share.clone(); - if old_share.owner.is_zero() { - share_user = - SharesTokenUser { - owner: get_caller_address(), - token_address: coin_address, - amount_owned: amount, - amount_buy: amount, - amount_sell: 0, - created_at: get_block_timestamp(), - total_paid: total_price, - }; - let total_key_share = self.total_shares_keys.read(); - self.total_shares_keys.write(total_key_share + 1); - } else { - share_user.total_paid += total_price; - share_user.amount_owned += amount; - share_user.amount_buy += amount; - } - // pool_coin.price = total_price / amount; - - // Check if liquidity threshold raise - let threshold = self.threshold_liquidity.read(); - let threshold_mc = self.threshold_market_cap.read(); - // println!("threshold {:?}", threshold); - // println!("pool_coin.liquidity_raised {:?}", pool_coin.liquidity_raised); - - let mc = (pool_coin.price * total_supply_memecoin); - // TODO add liquidity launch - // TOTAL_SUPPLY / 5 - // 20% go the liquidity - // 80% bought by others - - // TODO check reetrancy guard - // Update state - self - .shares_by_users - .entry((get_caller_address(), coin_address)) - .write(share_user.clone()); - self.launched_coins.entry(coin_address).write(pool_coin.clone()); - - // TODO finish test and fix - // Fix price of the last - if pool_coin.liquidity_raised >= threshold { - self - .emit( - LiquidityCanBeAdded { - pool: pool_coin.token_address.clone(), - asset: pool_coin.token_address.clone(), - quote_token_address: pool_coin.token_quote.token_address.clone(), - } - ); - // self._add_liquidity(coin_address, SupportedExchanges::Jediswap); - // self._add_liquidity(coin_address, SupportedExchanges::Ekubo); - // TODO fix add liquidity ekubo - // self._add_liquidity_ekubo(coin_address); - } - - self - .emit( - BuyToken { - caller: get_caller_address(), - token_address: coin_address, - amount: amount, - price: total_price, - protocol_fee: amount_protocol_fee, - // creator_fee: 0, - last_price: old_price, - timestamp: get_block_timestamp(), - quote_amount: quote_amount - } - ); - } - - - // TODO finish and fix - fn sell_coin(ref self: ContractState, coin_address: ContractAddress, quote_amount: u256) { - let old_pool = self.launched_coins.read(coin_address); - assert(!old_pool.owner.is_zero(), 'coin not found'); - - let caller = get_caller_address(); - let mut old_share = self.shares_by_users.read((get_caller_address(), coin_address)); - - let mut share_user = old_share.clone(); - - // TODO erc20 token transfer - let total_supply = old_pool.total_supply; - let token_quote = old_pool.token_quote.clone(); - let quote_token_address = token_quote.token_address.clone(); - assert(old_pool.liquidity_raised >= quote_amount, 'liquidity <= amount'); - assert(old_pool.is_liquidity_launch == false, 'token tradeable'); - - // TODO fix this function - // let mut amount = self - // ._get_coin_amount_by_quote_amount(coin_address, quote_amount, true); - - // Todo check user amount fee creator if needed - let creator_fee_percent = self.creator_fee_percent.read(); - let protocol_fee_percent = self.protocol_fee_percent.read(); - - let amount_protocol_fee: u256 = quote_amount * protocol_fee_percent / BPS; - let amount_creator_fee = quote_amount * creator_fee_percent / BPS; - let remain_liquidity = quote_amount - amount_protocol_fee; - // let amount_to_user: u256 = quote_amount - amount_protocol_fee - amount_creator_fee; - - let mut amount = get_amount_by_type_of_coin_or_quote( - old_pool.clone(), coin_address.clone(), remain_liquidity.clone(), false, true - ); - - // Verify Amount owned - assert(old_pool.total_supply >= quote_amount, 'above supply'); - assert(share_user.amount_owned >= amount, 'above supply'); - - // let mut total_price = amount; - // println!("amount {:?}", amount); - // println!("quote_amount {:?}", quote_amount); - // println!("total_price {:?}", total_price); - let erc20 = IERC20Dispatcher { contract_address: quote_token_address }; - - // Ensure fee percentages are within valid bounds - assert( - protocol_fee_percent <= MAX_FEE_PROTOCOL - && protocol_fee_percent >= MIN_FEE_PROTOCOL, - 'protocol fee out' - ); - // assert( - // creator_fee_percent <= MAX_FEE_CREATOR && creator_fee_percent >= MIN_FEE_CREATOR, - // 'creator_fee out' - // ); - - // assert!(old_share.amount_owned >= amount, "share to sell > supply"); - // println!("amount{:?}", amount); - // assert!(total_supply >= quote_amount, "share to sell > supply"); - // assert( old_pool.liquidity_raised >= quote_amount, 'liquidity_raised <= amount'); - - let old_price = old_pool.price.clone(); - let total_price = old_pool.price.clone(); - // Update keys with new values - let mut pool_update = old_pool.clone(); - - // let remain_liquidity = total_price ; - assert(old_pool.liquidity_raised >= remain_liquidity, 'liquidity <= amount'); - - // Ensure fee calculations are correct - // assert( - // amount_to_user + amount_protocol_fee + amount_creator_fee == quote_amount, - // 'fee calculation mismatch' - // ); - - // Assertion: Check if the contract has enough quote tokens to transfer - let contract_quote_balance = erc20.balance_of(get_contract_address()); - assert!( - contract_quote_balance >= quote_amount, - "contract has insufficient quote token balance" - ); - - // Transfer protocol fee to the designated destination - if amount_protocol_fee > 0 { - erc20.transfer(self.protocol_fee_destination.read(), amount_protocol_fee); - } - - // Transfer the remaining quote amount to the user - if remain_liquidity > 0 { - erc20.transfer(caller, remain_liquidity); - } - - // Assertion: Ensure the user receives the correct amount - let user_received = erc20.balance_of(caller); - assert(user_received >= remain_liquidity, 'user not receive amount'); - - // TODO sell coin if it's already sendable and transferable - // ENABLE if direct launch coin - // let memecoin = IERC20Dispatcher { contract_address: coin_address }; - // memecoin.transfer_from(get_caller_address(), get_contract_address(), amount); - - // TODO fix amount owned and sellable. - // Update share user coin - share_user.amount_owned -= amount; - share_user.amount_sell += amount; - - // TODO check reetrancy guard - - // Assertion: Ensure pool liquidity remains consistent - assert!( - old_pool.liquidity_raised >= quote_amount, "pool liquidity inconsistency after sale" - ); - - // TODO finish update state - // pool_update.price = total_price; - pool_update.liquidity_raised -= remain_liquidity; - pool_update.total_token_holded -= amount; - pool_update.available_supply += amount; - - // Assertion: Ensure the pool's liquidity and token holded are updated correctly - // assert!( - // pool_update.liquidity_raised + quote_amount == old_pool.liquidity_raised, - // "liquidity_raised mismatch after update" - // ); - // assert!( - // pool_update.total_token_holded - // + self - // ._get_coin_amount_by_quote_amount( - // coin_address, quote_amount, true - // ) == old_pool - // .total_token_holded, - // "total_token_holded mismatch after update" - // ); - - self - .shares_by_users - .entry((get_caller_address(), coin_address.clone())) - .write(share_user.clone()); - self.launched_coins.entry(coin_address.clone()).write(pool_update.clone()); - self - .emit( - SellToken { - caller: caller, - key_user: coin_address, - amount: quote_amount, - price: total_price, // Adjust if necessary - protocol_fee: amount_protocol_fee, - creator_fee: amount_creator_fee, - timestamp: get_block_timestamp(), - last_price: old_pool.price, - } - ); - } - - - // TODO finish check - // Launch liquidity if threshold ok - // Add more exchanges. Start with EKUBO by default - fn launch_liquidity( - ref self: ContractState, coin_address: ContractAddress, // exchange:SupportedExchanges - ) { - // TODO auto distrib and claim? - - let caller = get_caller_address(); - - let pool = self.launched_coins.read(coin_address); - - assert(caller == pool.owner, errors::OWNER_DIFFERENT); - - self._add_liquidity_ekubo(coin_address); - // self._add_liquidity(coin_address, SupportedExchanges::Jediswap, ekubo_pool_params); - // self._add_liquidity(coin_address, SupportedExchanges::Ekubo, ekubo_pool_params); - } - fn add_liquidity_jediswap(ref self: ContractState, coin_address: ContractAddress) { - // TODO auto distrib and claim? - let caller = get_caller_address(); - - let pool = self.launched_coins.read(coin_address); - - assert(caller == pool.owner, errors::OWNER_DIFFERENT); - - self._add_liquidity_jediswap(coin_address); - // self._add_liquidity(coin_address, SupportedExchanges::Jediswap, ekubo_pool_params); - // self._add_liquidity(coin_address, SupportedExchanges::Ekubo, ekubo_pool_params); - } - - - // TODO Finish this function - // Claim coin if liquidity is sent - // Check and modify the share of user - fn claim_coin_buy(ref self: ContractState, coin_address: ContractAddress, amount: u256) { - let caller = get_contract_address(); - // Verify if liquidity launch - let mut launch = self.launched_coins.read(coin_address); - assert(launch.is_liquidity_launch == true, 'not launch yet'); - - // Verify share of user - let mut share_user = self.shares_by_users.read((get_caller_address(), coin_address)); - - let max_amount_claimable = share_user.amount_owned; - assert(max_amount_claimable >= amount, 'share below'); - - // Transfer memecoin - let memecoin = IERC20Dispatcher { contract_address: coin_address }; - memecoin.transfer(caller, amount); - - // Update new share and emit event - share_user.amount_owned -= amount; - self.shares_by_users.entry((get_caller_address(), coin_address)).write(share_user); - - self - .emit( - TokenClaimed { - token_address: coin_address, - owner: caller, - timestamp: get_block_timestamp(), - amount, - } - ); - } - - // TODO finish add Metadata - fn add_metadata( - ref self: ContractState, coin_address: ContractAddress, metadata: MetadataLaunch - ) { - let caller = get_contract_address(); - // Verify if caller is owner - let mut launch = self.launched_coins.read(coin_address); - assert(launch.owner == caller, 'not owner'); - - // Add or update metadata - - self.metadata_coins.entry(coin_address).write(metadata.clone()); - self - .emit( - MetadataCoinAdded { - token_address: coin_address, - url: metadata.url, - timestamp: get_block_timestamp(), - nostr_event_id: metadata.nostr_event_id, - } - ); - } - - - fn get_default_token(self: @ContractState) -> TokenQuoteBuyCoin { - self.default_token.read() - } - - fn get_threshold_liquidity(self: @ContractState) -> u256 { - self.threshold_liquidity.read() - } - - - fn get_coin_launch(self: @ContractState, key_user: ContractAddress,) -> TokenLaunch { - self.launched_coins.read(key_user) - } - - fn get_share_key_of_user( - self: @ContractState, owner: ContractAddress, key_user: ContractAddress, - ) -> SharesTokenUser { - self.shares_by_users.read((owner, key_user)) - } - - fn get_all_coins(self: @ContractState) -> Span { - let max_coin_id = self.total_token.read() + 1; - let mut coins: Array = ArrayTrait::new(); - let mut i = 0; //Since the stream id starts from 0 - loop { - if i >= max_coin_id {} - let coin = self.array_coins.read(i); - if coin.owner.is_zero() { - break coins.span(); - } - coins.append(coin); - i += 1; - } - } - - fn get_all_launch(self: @ContractState) -> Span { - let max_key_id = self.total_launch.read() + 1; - let mut launches: Array = ArrayTrait::new(); - let mut i = 0; //Since the stream id starts from 0 - loop { - if i >= max_key_id {} - let pool = self.array_launched_coins.read(i); - if pool.owner.is_zero() { - break launches.span(); - } - launches.append(pool); - i += 1; - } - } - - // The function calculates the amiunt of quote_token you need to buy a coin in the pool - fn get_amount_by_type_of_coin_or_quote( - self: @ContractState, - coin_address: ContractAddress, - amount: u256, - is_decreased: bool, - is_quote_amount: bool - ) -> u256 { - let pool = self.launched_coins.read(coin_address).clone(); - get_amount_by_type_of_coin_or_quote( - pool.clone(), coin_address, amount, is_decreased, is_quote_amount - ) - // self - // .get_amount_by_type_of_coin_or_quote( - // coin_address, amount, is_decreased, is_quote_amount - // ) - } - - fn get_coin_amount_by_quote_amount( - self: @ContractState, - coin_address: ContractAddress, - quote_amount: u256, - is_decreased: bool - ) -> u256 { - let pool = self.launched_coins.read(coin_address).clone(); - - // self._get_coin_amount_by_quote_amount(coin_address, quote_amount, is_decreased) - get_coin_amount_by_quote_amount(pool.clone(), quote_amount, is_decreased) - } - - // fn get_quote_paid_by_amount_coin( - // self: @ContractState, - // coin_address: ContractAddress, - // quote_amount: u256, - // is_decreased: bool - // ) -> u256 { - // self._get_quote_paid_by_amount_coin(coin_address, quote_amount, is_decreased) - // } - - //TODO refac - fn add_liquidity_unrug( - ref self: ContractState, - coin_address: ContractAddress, - launch_params: LaunchParameters, - ekubo_pool_params: EkuboPoolParameters - ) -> (u64, EkuboLP) { - //TODO restrict fn? - - self._add_internal_liquidity_unrug(coin_address, launch_params, ekubo_pool_params) - // INTEGRATION not working - // self._add_liquidity_unrug(launch_params, ekubo_pool_params) - } - - //TODO refac - fn add_liquidity_unrug_lp( - ref self: ContractState, - coin_address: ContractAddress, - quote_address: ContractAddress, - lp_supply: u256, - launch_params: LaunchParameters, - ekubo_pool_params: EkuboPoolParameters - ) -> (u64, EkuboLP) { - //TODO restrict fn? - - let caller = get_caller_address(); - self - ._add_internal_liquidity_unrug_lp( - caller, coin_address, quote_address, lp_supply, launch_params, ekubo_pool_params - ) - // INTEGRATION not working - // self._add_liquidity_unrug(launch_params, ekubo_pool_params) - } - - fn create_unrug_token( - ref self: ContractState, - owner: ContractAddress, - name: felt252, - symbol: felt252, - initial_supply: u256, - contract_address_salt: felt252, - is_launch_bonding_now: bool, - ) -> ContractAddress { - let caller = get_caller_address(); - let creator = get_caller_address(); - let contract_address = get_contract_address(); - let owner = get_caller_address(); - if is_launch_bonding_now == true { - let token_address = self - ._create_token( - contract_address, - caller, - symbol, - name, - initial_supply, - contract_address_salt, - true - ); - self._launch_token(token_address, caller, contract_address, true); - token_address - } else { - let token_address = self - ._create_token( - contract_address, - caller, - symbol, - name, - initial_supply, - contract_address_salt, - true - ); - let contract_address = get_contract_address(); - - let mut token = Token { - token_address: token_address, - owner: owner, - creator: creator, - name, - symbol, - total_supply: initial_supply, - initial_supply: initial_supply, - created_at: get_block_timestamp(), - token_type: Option::None, - is_unruggable: true - }; - self.token_created.entry(token_address).write(token); - token_address - } - } - - fn add_liquidity_ekubo( - ref self: ContractState, coin_address: ContractAddress, - // params: EkuboLaunchParameters - // ) -> Span { - ) -> (u64, EkuboLP) { - let caller = get_caller_address(); - let pool = self.launched_coins.read(coin_address); - assert(caller == pool.owner, errors::OWNER_DIFFERENT); - self._add_liquidity_ekubo(coin_address) - } - } - - #[external(v0)] - impl LockerImpl of ILocker { - /// Callback function called by the core contract. - fn locked(ref self: ContractState, id: u32, data: Span) -> Span { - let core_address = self.core.read(); - let core = ICoreDispatcher { contract_address: core_address }; - // Register the token in Ekubo Registry - let registry_address = self.ekubo_registry.read(); - // println!("IN HERE: {}", 1); - let dex_address = self.core.read(); - let ekubo_core_address = self.core.read(); - let ekubo_exchange_address = self.ekubo_exchange_address.read(); - let positions_address = self.positions.read(); - - match consume_callback_data::(core, data) { - CallbackData::LaunchCallback(params) => { - let launch_params: EkuboLaunchParameters = params.params; - let (token0, token1) = sort_tokens( - launch_params.token_address, launch_params.quote_address - ); - let memecoin = EKIERC20Dispatcher { - contract_address: launch_params.token_address - }; - let base_token = EKIERC20Dispatcher { - contract_address: launch_params.quote_address - }; - let registry = ITokenRegistryDispatcher { contract_address: registry_address }; - // println!("IN HERE: {}", 2); - - let pool_key = PoolKey { - token0: token0, - token1: token1, - fee: launch_params.pool_params.fee, - tick_spacing: launch_params.pool_params.tick_spacing, - extension: 0.try_into().unwrap(), - }; - - let lp_supply = launch_params.lp_supply.clone(); - // println!("IN HERE: {}", 3); - - // The initial_tick must correspond to the wanted initial price in quote/MEME - // The ekubo prices are always in TOKEN1/TOKEN0. - // The initial_tick is the lower bound if the quote is token1, the upper bound - // otherwise. - let is_token1_quote = launch_params.quote_address == token1; - let (initial_tick, full_range_bounds) = get_initial_tick_from_starting_price( - launch_params.pool_params.starting_price, - launch_params.pool_params.bound, - is_token1_quote - ); - - let pool = self.launched_coins.read(launch_params.token_address); - - // println!("IN HERE: {}", 4); - - base_token.approve(registry.contract_address, pool.liquidity_raised); - base_token.approve(ekubo_core_address, pool.liquidity_raised); - base_token.approve(positions_address, lp_supply); - - memecoin.approve(registry.contract_address, lp_supply); - memecoin.approve(positions_address, lp_supply); - memecoin.approve(dex_address, lp_supply); - memecoin.approve(ekubo_core_address, lp_supply); - // memecoin.transfer(registry.contract_address, 1000000000000000000); - // memecoin.transfer(registry.contract_address, pool.available_supply); - // memecoin.transfer(registry.contract_address, pool.available_supply); - // println!("transfer before register"); - registry - .register_token( - EKIERC20Dispatcher { contract_address: launch_params.token_address } - ); - - // println!("initial tick {:?}", initial_tick); - // Initialize the pool at the initial tick. - // println!("init pool"); - - core.maybe_initialize_pool(:pool_key, :initial_tick); - // println!("init pool"); - - // println!("IN HERE: {}", 5); - // println!("supply liq"); - - // 2. Provide the liquidity to actually initialize the public pool with - // The pool bounds must be set according to the tick spacing. - // The bounds were previously computed to provide yield covering the entire - // interval [lower_bound, starting_price] or [starting_price, upper_bound] - // depending on the quote. - let id = self - ._supply_liquidity_ekubo( - pool_key, - launch_params.token_address, - launch_params.lp_supply, - full_range_bounds - ); - - // println!("IN HERE: {}", 6); - - let position = EkuboLP { - // let position = @EkuboLP { - owner: launch_params.owner, - quote_address: launch_params.quote_address, - pool_key, - bounds: full_range_bounds - }; - // println!("position owner {:?}", owner); - // println!("position quote_address {:?}", quote_address); - - // At this point, the pool is composed by: - // n% of liquidity at precise starting tick, reserved for the team to buy - // the rest of the liquidity, in bounds [starting_price, +inf]; - - let mut return_data: Array = Default::default(); - Serde::serialize(@id, ref return_data); - Serde::serialize( - @EkuboLP { - owner: launch_params.owner, - quote_address: launch_params.quote_address, - pool_key, - bounds: full_range_bounds - }, - ref return_data - ); - return_data.span() - } - // CallbackData::WithdrawFeesCallback(params) => { - // let WithdrawFeesCallback{id, liquidity_type, recipient } = params; - // let positions = self.positions.read(); - // let EkuboLP{owner, quote_address: _, pool_key, bounds } = liquidity_type; - // let pool_key = PoolKey { - // token0: pool_key.token0, - // token1: pool_key.token1, - // fee: pool_key.fee, - // tick_spacing: pool_key.tick_spacing, - // extension: pool_key.extension, - // }; - // let bounds = Bounds { lower: bounds.lower, upper: bounds.upper, }; - // positions.collect_fees(id, pool_key, bounds); - - // // Transfer to recipient is done after the callback - // let mut return_data = Default::default(); - // Serde::serialize(@pool_key.token0, ref return_data); - // Serde::serialize(@pool_key.token1, ref return_data); - // return_data - // }, - } - } - } - - // // Could be a group of functions about a same topic - #[generate_trait] - impl InternalFunctions of InternalFunctionsTrait { - fn _create_token( - ref self: ContractState, - recipient: ContractAddress, - owner: ContractAddress, - symbol: felt252, - name: felt252, - initial_supply: u256, - contract_address_salt: felt252, - is_unruggable: bool - ) -> ContractAddress { - let mut calldata = array![name.into(), symbol.into()]; - Serde::serialize(@initial_supply, ref calldata); - Serde::serialize(@recipient, ref calldata); - Serde::serialize(@18, ref calldata); - - let (token_address, _) = deploy_syscall( - self.coin_class_hash.read(), contract_address_salt, calldata.span(), false - ) - .unwrap(); - // .unwrap_syscall(); - // println!("token address {:?}", token_address); - - let token = Token { - token_address: token_address, - owner: recipient, - creator: owner, - name, - symbol, - total_supply: initial_supply, - initial_supply: initial_supply, - created_at: get_block_timestamp(), - token_type: Option::None, - is_unruggable: is_unruggable - }; - - self.token_created.entry(token_address).write(token); - - let total_token = self.total_token.read(); - if total_token == 0 { - self.total_token.write(1); - self.array_coins.entry(0).write(token); - } else { - self.total_token.write(total_token + 1); - self.array_coins.entry(total_token).write(token); - } - - self - .emit( - CreateToken { - caller: get_caller_address(), - token_address: token_address, - symbol: symbol, - name: name, - initial_supply, - total_supply: initial_supply.clone(), - is_unruggable: is_unruggable - } - ); - token_address - } - - - fn _launch_token( - ref self: ContractState, - coin_address: ContractAddress, - caller: ContractAddress, - creator: ContractAddress, - is_unruggable: bool - ) { - // let caller = get_caller_address(); - let token = self.token_created.read(coin_address); - - // TODO - // Maybe not needed because you can also create the coin everyhwhere (Unrug) and launch - let mut token_to_use = self.default_token.read(); - let mut quote_token_address = token_to_use.token_address.clone(); - let bond_type = BondingType::Linear; - // let erc20 = IERC20Dispatcher { contract_address: quote_token_address }; - let memecoin = IERC20Dispatcher { contract_address: coin_address }; - let total_supply = memecoin.total_supply(); - let threshold_liquidity = self.threshold_liquidity.read(); - let protocol_fee_percent = self.protocol_fee_percent.read(); - let creator_fee_percent = self.creator_fee_percent.read(); - - // let threshold = pool.threshold_liquidity; - - // TODO calculate initial key price based on - // MC - // Threshold liquidity - // total supply - - // Total supply / 5 to get 20% of supply add after threshold - let liquidity_supply = total_supply / LIQUIDITY_RATIO; - let supply_distribution = total_supply - liquidity_supply; - let liquidity_available = total_supply - liquidity_supply; - - // let (slope, init_price) = self._calculate_pricing(total_supply - liquidity_supply); - let starting_price = calculate_pricing( - threshold_liquidity.clone(), supply_distribution.clone() - ); - let slope = calculate_slope( - threshold_liquidity.clone(), starting_price.clone(), supply_distribution.clone() - ); - // let starting_price = threshold_liquidity / total_supply; - // // @TODO Deploy an ERC404 - // // Option for liquidity providing and Trading - let launch_token_pump = TokenLaunch { - owner: caller, - creator: caller, - token_address: coin_address, // CREATE 404 - total_supply: total_supply, - // available_supply: total_supply, - available_supply: supply_distribution, - initial_available_supply: supply_distribution, - initial_pool_supply: liquidity_supply, - // available_supply:liquidity_supply, - // Todo price by pricetype after fix Enum instantiate - bonding_curve_type: Option::Some(bond_type), - // bonding_curve_type: BondingType, - created_at: get_block_timestamp(), - token_quote: token_to_use.clone(), - starting_price: starting_price.clone(), - // starting_price: token_to_use.starting_price, - price: starting_price.clone(), - // price:init_price, - liquidity_raised: 0_u256, - total_token_holded: 0_u256, - is_liquidity_launch: false, - slope: slope, - threshold_liquidity: threshold_liquidity, - liquidity_type: Option::None, - protocol_fee_percent: protocol_fee_percent, - creator_fee_percent: creator_fee_percent - }; - // Send supply need to launch your coin - let amount_needed = total_supply.clone(); - // println!("amount_needed {:?}", amount_needed); - let allowance = memecoin.allowance(caller, get_contract_address()); - // println!("test allowance contract {:?}", allowance); - let balance_contract = memecoin.balance_of(get_contract_address()); - - let is_memecoin = is_unruggable; - // let is_memecoin = factory.is_memecoin(memecoin.contract_address); - // if balance_contract < total_supply && !is_memecoin { - if balance_contract < total_supply { - // && !is_memecoin - assert(allowance >= amount_needed, 'no supply provided'); - if allowance >= amount_needed { - // println!("allowance > amount_needed{:?}", allowance > amount_needed); - memecoin - .transfer_from( - caller, get_contract_address(), total_supply - balance_contract - ); - } - } - - // memecoin.transfer_from(get_caller_address(), get_contract_address(), amount_needed); - self.launched_coins.entry(coin_address).write(launch_token_pump.clone()); - - let total_launch = self.total_launch.read(); - if total_launch == 0 { - self.total_launch.write(1); - self.array_launched_coins.entry(0).write(launch_token_pump); - } else { - self.total_launch.write(total_launch + 1); - self.array_launched_coins.entry(total_launch).write(launch_token_pump); - } - self - .emit( - CreateLaunch { - caller: get_caller_address(), - token_address: coin_address, - amount: 0, - price: starting_price, - total_supply: total_supply, - slope: slope, - threshold_liquidity: threshold_liquidity, - quote_token_address: quote_token_address, - is_unruggable: is_unruggable - } - ); - } - - // TODO add liquidity to Ekubo, Jediswap and others exchanges enabled - // TODO Increased liquidity if pool already exist - fn _add_liquidity( - ref self: ContractState, coin_address: ContractAddress, exchange: SupportedExchanges - ) { - match exchange { - SupportedExchanges::Jediswap => { self._add_liquidity_jediswap(coin_address) }, - SupportedExchanges::Ekubo => { self._add_liquidity_ekubo(coin_address); }, - } - let mut launch_to_update = self.launched_coins.read(coin_address); - launch_to_update.is_liquidity_launch = true; - self.launched_coins.entry(coin_address).write(launch_to_update.clone()); - } - - - fn _supply_liquidity_ekubo( - ref self: ContractState, - pool_key: PoolKey, - token: ContractAddress, - amount: u256, - bounds: Bounds - ) -> u64 { - // println!("mint deposit NOW HERE: {}", 1); - - let positions_address = self.positions.read(); - let positions = IPositionsDispatcher { contract_address: positions_address }; - // println!("mint deposit NOW HERE: {}", 2); - - // The token must be transferred to the positions contract before calling mint. - IERC20Dispatcher { contract_address: token } - .transfer(recipient: positions.contract_address, :amount); - // println!("mint deposit NOW HERE: {}", 3); - - let (id, liquidity) = positions.mint_and_deposit(pool_key, bounds, min_liquidity: 0); - // let (id, liquidity, _, _) = positions - // .mint_and_deposit_and_clear_both(pool_key, bounds, min_liquidity: 0); - // println!("mint deposit NOW HERE: {}", 4); - id - } - - fn _add_liquidity_ekubo( - ref self: ContractState, coin_address: ContractAddress, - // params: EkuboLaunchParameters - ) -> (u64, EkuboLP) { - // TODO params of Ekubo launch - // Init price and params of liquidity - - // TODO assert of threshold and MC reached - let launch = self.launched_coins.read(coin_address); - assert(launch.liquidity_raised >= launch.threshold_liquidity, 'no threshold raised'); - assert(launch.is_liquidity_launch == false, 'liquidity already launch'); - - // TODO calculate price - - // let launch_price = launch.initial_pool_supply / launch.threshold_liquidity; - // println!("launch_price {:?}", launch_price); - - // let price_u128:u128=launch_price.try_into().unwrap(); - // println!("price_u128 {:?}", price_u128); - - // let starting_price = i129 { sign: true, mag: 100_u128 }; - // let starting_price = i129 { sign: true, mag: 100_u128 }; - // let starting_price = i129 { sign: true, mag: price_u128 }; - let starting_price: i129 = calculate_starting_price_launch( - launch.initial_pool_supply.clone(), launch.threshold_liquidity.clone() - ); - let lp_meme_supply = launch.initial_pool_supply; - - // let lp_meme_supply = launch.initial_available_supply - launch.available_supply; - - let params: EkuboLaunchParameters = EkuboLaunchParameters { - owner: launch.owner, - token_address: launch.token_address, - quote_address: launch.token_quote.token_address, - lp_supply: lp_meme_supply, - // lp_supply: launch.liquidity_raised, - pool_params: EkuboPoolParameters { - fee: 0xc49ba5e353f7d00000000000000000, - tick_spacing: 5000, - starting_price, - bound: calculate_aligned_bound_mag(starting_price, 2, 5000), - } - }; - - // println!("Bound computed: {}", params.pool_params.bound); - - // Register the token in Ekubo Registry - // let registry_address = self.ekubo_registry.read(); - // let registry = ITokenRegistryDispatcher { contract_address: registry_address }; - - let ekubo_core_address = self.core.read(); - let ekubo_exchange_address = self.ekubo_exchange_address.read(); - let memecoin = EKIERC20Dispatcher { contract_address: params.token_address }; - //TODO token decimal, amount of 1 token? - - // println!("RIGHT HERE: {}", 1); - - let pool = self.launched_coins.read(coin_address); - let dex_address = self.core.read(); - let positions_ekubo = self.positions.read(); - memecoin.approve(ekubo_exchange_address, lp_meme_supply); - memecoin.approve(ekubo_core_address, lp_meme_supply); - memecoin.approve(positions_ekubo, lp_meme_supply); - assert!(memecoin.contract_address == params.token_address, "Token address mismatch"); - let base_token = EKIERC20Dispatcher { contract_address: params.quote_address }; - //TODO token decimal, amount of 1 token? - // let pool = self.launched_coins.read(coin_address); - base_token.approve(ekubo_exchange_address, pool.liquidity_raised); - base_token.approve(ekubo_core_address, pool.liquidity_raised); - let core = ICoreDispatcher { contract_address: ekubo_core_address }; - // Call the core with a callback to deposit and mint the LP tokens. - - // println!("HERE launch callback: {}", 2); - - let (id, position) = call_core_with_callback::< - // let span = call_core_with_callbac00k::< - CallbackData, (u64, EkuboLP) - >(core, @CallbackData::LaunchCallback(LaunchCallback { params })); - // let (id,position) = self._supply_liquidity_ekubo_and_mint(coin_address, params); - //TODO emit event - let id_cast: u256 = id.try_into().unwrap(); - - // println!("RIGHT HERE: {}", 3); - - let mut launch_to_update = self.launched_coins.read(coin_address); - launch_to_update.is_liquidity_launch = true; - self.launched_coins.entry(coin_address).write(launch_to_update.clone()); - - // println!("RIGHT HERE: {}", 4); - - self - .emit( - LiquidityCreated { - id: id_cast, - pool: coin_address, - asset: coin_address, - quote_token_address: base_token.contract_address, - owner: launch.owner, - exchange: SupportedExchanges::Ekubo, - is_unruggable: false - } - ); - - (id, position) - } - - /// TODO fix change - fn _check_common_launch_parameters( - ref self: ContractState, launch_parameters: LaunchParameters - ) -> (u256, u8) { - let LaunchParameters { memecoin_address, - transfer_restriction_delay, - max_percentage_buy_launch, - quote_address, - initial_holders, - initial_holders_amounts } = - launch_parameters; - let memecoin = IMemecoinDispatcher { contract_address: memecoin_address }; - let erc20 = IERC20Dispatcher { contract_address: memecoin_address }; - - // TODO fix assert - // assert(self.is_memecoin(memecoin_address), errors::NOT_UNRUGGABLE); - // assert(!self.is_memecoin(quote_address), errors::QUOTE_TOKEN_IS_MEMECOIN); - assert(!memecoin.is_launched(), errors::ALREADY_LAUNCHED); - // assert(get_caller_address() == memecoin.owner(), errors::CALLER_NOT_OWNER); - assert(initial_holders.len() == initial_holders_amounts.len(), errors::ARRAYS_LEN_DIF); - assert(initial_holders.len() <= MAX_HOLDERS_LAUNCH.into(), errors::MAX_HOLDERS_REACHED); - - let initial_supply = erc20.total_supply(); - - // Check that the sum of the amounts of initial holders does not exceed the max - // allocatable supply for a team. - let max_team_allocation = initial_supply - .percent_mul(MAX_SUPPLY_PERCENTAGE_TEAM_ALLOCATION.into()); - let mut team_allocation: u256 = 0; - let mut i: usize = 0; - loop { - if i == initial_holders.len() { - break; - } - - let address = *initial_holders.at(i); - let amount = *initial_holders_amounts.at(i); - - team_allocation += amount; - assert(team_allocation <= max_team_allocation, errors::MAX_TEAM_ALLOCATION_REACHED); - i += 1; - }; - - (team_allocation, unique_count(initial_holders).try_into().unwrap()) - } - - fn _add_internal_liquidity_unrug( - ref self: ContractState, - coin_address: ContractAddress, - launch_params: LaunchParameters, - ekubo_pool_params: EkuboPoolParameters - ) -> (u64, EkuboLP) { - let launch = self.launched_coins.read(coin_address); - // let starting_price = i129 { sign: true, mag: 100_u128 }; - - // let starting_price: i129 = self._calculate_starting_price_launch( - // launch.initial_pool_supply.clone(), launch.threshold_liquidity.clone() - // ); - let starting_price: i129 = calculate_starting_price_launch( - launch.initial_pool_supply.clone(), launch.threshold_liquidity.clone() - ); - - let lp_meme_supply = launch.initial_available_supply - launch.available_supply; - - let lp_meme_supply = launch.initial_pool_supply; - let lp_supply = launch.initial_pool_supply; - - let params: EkuboLaunchParameters = EkuboLaunchParameters { - owner: launch.owner, - token_address: launch.token_address, - quote_address: launch.token_quote.token_address, - lp_supply: lp_meme_supply, - // lp_supply: launch.liquidity_raised, - pool_params: EkuboPoolParameters { - fee: 0xc49ba5e353f7d00000000000000000, - tick_spacing: 5000, - starting_price, - bound: calculate_aligned_bound_mag(starting_price, 2, 5000), - } - }; - // let params: EkuboLaunchParameters = EkuboLaunchParameters { - // owner: launch.owner, - // token_address: launch.token_address, - // quote_address: launch.token_quote.token_address, - // lp_supply: lp_meme_supply, - // // lp_supply: launch.liquidity_raised, - // pool_params: EkuboPoolParameters { - // fee: 0xc49ba5e353f7d00000000000000000, - // tick_spacing: 5982, - // starting_price, - // bound: 88719042, - // } - // }; - - let (team_allocation, pre_holders) = self - ._check_common_launch_parameters(launch_params); - - assert(launch.liquidity_raised >= launch.threshold_liquidity, 'no threshold raised'); - assert(launch.is_liquidity_launch == false, 'liquidity already launch'); - - assert( - ekubo_pool_params.fee <= 0x51eb851eb851ec00000000000000000, errors::FEE_TOO_HIGH - ); - assert(ekubo_pool_params.tick_spacing >= 5982, errors::TICK_SPACING_TOO_LOW); - assert(ekubo_pool_params.tick_spacing <= 19802, errors::TICK_SPACING_TOO_HIGH); - assert(ekubo_pool_params.bound >= 88712960, errors::BOUND_TOO_LOW); - - let LaunchParameters { memecoin_address, - transfer_restriction_delay, - max_percentage_buy_launch, - quote_address, - initial_holders, - initial_holders_amounts } = - launch_params; - - // let launchpad_address = self.exchange_address(SupportedExchanges::Ekubo); - let launchpad_address = self.ekubo_exchange_address.read(); - - // let launchpad_address = self.exchange_address(SupportedExchanges::Ekubo); - assert(launchpad_address.is_non_zero(), errors::EXCHANGE_ADDRESS_ZERO); - assert(ekubo_pool_params.starting_price.mag.is_non_zero(), errors::PRICE_ZERO); - - let erc20 = IERC20Dispatcher { contract_address: coin_address }; - let ekubo_core_address = self.core.read(); - - let memecoin = IERC20Dispatcher { contract_address: coin_address }; - memecoin.approve(ekubo_core_address, lp_supply); - - let core = ICoreDispatcher { contract_address: ekubo_core_address }; - - let (id, position) = call_core_with_callback::< - CallbackData, (u64, EkuboLP) - >(core, @CallbackData::LaunchCallback(LaunchCallback { params })); - - distribute_team_alloc(erc20, initial_holders, initial_holders_amounts); - - let memecoin = IMemecoinDispatcher { contract_address: coin_address }; - - memecoin - .set_launched( - LiquidityType::EkuboNFT(id), - LiquidityParameters::Ekubo( - EkuboLiquidityParameters { - quote_address, ekubo_pool_parameters: ekubo_pool_params - } - ), - :transfer_restriction_delay, - :max_percentage_buy_launch, - :team_allocation, - ); - // self - // .emit( - // MemecoinLaunched { - // memecoin_address, quote_token: quote_address, exchange_name: 'Ekubo' - // } - // ); - (id, position) - } - - - fn _add_internal_liquidity_unrug_lp( - ref self: ContractState, - caller: ContractAddress, - coin_address: ContractAddress, - quote_address: ContractAddress, - lp_supply: u256, - launch_params: LaunchParameters, - ekubo_pool_params: EkuboPoolParameters - ) -> (u64, EkuboLP) { - let starting_price = i129 { sign: true, mag: 10_u128 }; - - let params: EkuboLaunchParameters = EkuboLaunchParameters { - owner: caller, - token_address: coin_address, - quote_address: quote_address, - lp_supply: lp_supply, - // lp_supply: launch.liquidity_raised, - pool_params: ekubo_pool_params - }; - let (team_allocation, pre_holders) = self - ._check_common_launch_parameters(launch_params); - - assert( - ekubo_pool_params.fee <= 0x51eb851eb851ec00000000000000000, errors::FEE_TOO_HIGH - ); - assert(ekubo_pool_params.tick_spacing >= 5982, errors::TICK_SPACING_TOO_LOW); - assert(ekubo_pool_params.tick_spacing <= 19802, errors::TICK_SPACING_TOO_HIGH); - assert(ekubo_pool_params.bound >= 88712960, errors::BOUND_TOO_LOW); - - let LaunchParameters { memecoin_address, - transfer_restriction_delay, - max_percentage_buy_launch, - quote_address, - initial_holders, - initial_holders_amounts } = - launch_params; - - let launchpad_address = self.ekubo_exchange_address.read(); - assert(launchpad_address.is_non_zero(), errors::EXCHANGE_ADDRESS_ZERO); - assert(ekubo_pool_params.starting_price.mag.is_non_zero(), errors::PRICE_ZERO); - - let erc20 = IERC20Dispatcher { contract_address: coin_address }; - let ekubo_core_address = self.core.read(); - - let memecoin = IERC20Dispatcher { contract_address: coin_address }; - memecoin.approve(ekubo_core_address, lp_supply); - - let core = ICoreDispatcher { contract_address: ekubo_core_address }; - - let (id, position) = call_core_with_callback::< - CallbackData, (u64, EkuboLP) - >(core, @CallbackData::LaunchCallback(LaunchCallback { params })); - - distribute_team_alloc(erc20, initial_holders, initial_holders_amounts); - - let memecoin = IMemecoinDispatcher { contract_address: coin_address }; - - memecoin - .set_launched( - LiquidityType::EkuboNFT(id), - LiquidityParameters::Ekubo( - EkuboLiquidityParameters { - quote_address, ekubo_pool_parameters: ekubo_pool_params - } - ), - :transfer_restriction_delay, - :max_percentage_buy_launch, - :team_allocation, - ); - // self - // .emit( - // MemecoinLaunched { - // memecoin_address, quote_token: quote_address, exchange_name: 'Ekubo' - // } - // ); - (id, position) - } - - // TODO add liquidity or increase - // Better params of Mint - fn _add_liquidity_jediswap(ref self: ContractState, coin_address: ContractAddress) { - let mut factory_address = self.address_jediswap_factory_v2.read(); - let nft_router_address = self.address_jediswap_nft_router_v2.read(); - - if nft_router_address.is_zero() { - return; - } - let nft_router = IJediswapNFTRouterV2Dispatcher { - contract_address: nft_router_address - }; - - let facto_address = nft_router.factory(); - - if !facto_address.is_zero() { - factory_address = facto_address.clone(); - } - - if factory_address.is_zero() { - return; - } - // let jediswap_address = self.exchange_configs.read(SupportedExchanges::Jediswap); - // - let fee: u32 = 10_000; - let factory = IJediswapFactoryV2Dispatcher { contract_address: factory_address }; - let launch = self.launched_coins.read(coin_address); - let token_a = launch.token_address.clone(); - let asset_token_address = launch.token_address.clone(); - let quote_token_address = launch.token_quote.token_address.clone(); - let token_b = launch.token_quote.token_address.clone(); - // TODO tokens check - // assert!(token_a != token_b, "same token"); - // Look if pool already exist - // Init and Create pool if not exist - let mut pool: ContractAddress = factory.get_pool(token_a, token_b, fee); - let sqrt_price_X96 = 0; // TODO change sqrt_price_X96 - - // TODO check if pool exist - // Pool need to be create - // Better params for Liquidity launching - // let token_asset = IERC20Dispatcher { contract_address: token_a }; - - // TODO - // Used total supply if coin is minted - // let total_supply_now = token_asset.total_supply().clone(); - let total_supply = launch.total_supply.clone(); - let liquidity_raised = launch.liquidity_raised.clone(); - // let total_supply = launch.total_supply.clone(); - - let amount_coin_liq = total_supply / LIQUIDITY_RATIO; - let amount0_desired = 0; - let amount1_desired = 0; - let amount0_min = amount_coin_liq; - let amount1_min = liquidity_raised; - let tick_lower: i32 = 0; - let tick_upper: i32 = 0; - let deadline: u64 = get_block_timestamp(); - - // @TODO check mint params - - if pool.into() == 0_felt252 { - pool = factory.create_pool(token_a, token_b, fee); - pool = nft_router.create_and_initialize_pool(token_a, token_b, fee, sqrt_price_X96); - // TODO Increase liquidity with router if exist - // Approve token asset and quote to be transferred - let token_asset = IERC20Dispatcher { contract_address: token_a }; - let token_quote = IERC20Dispatcher { contract_address: token_b }; - token_asset.approve(nft_router_address, amount_coin_liq); - token_quote.approve(nft_router_address, launch.liquidity_raised); - // TODO verify Mint params - // Test snforge in Sepolia - let mint_params = MintParams { - token0: token_a, - token1: token_b, - fee: fee, - tick_lower: tick_lower, - tick_upper: tick_upper, - amount0_desired: amount0_desired, - amount1_desired: amount1_desired, - amount0_min: amount0_min, - amount1_min: amount1_min, - recipient: launch.owner, // TODO add - deadline: deadline, - }; - - let (token_id, _, _, _) = nft_router.mint(mint_params); - // TODO Locked LP token - self - .emit( - LiquidityCreated { - id: token_id, - pool: pool, - quote_token_address: quote_token_address, - // token_id:token_id, - owner: launch.owner, - asset: asset_token_address, - exchange: SupportedExchanges::Jediswap, - is_unruggable: false - } - ); - } else { // TODO - // Increase liquidity of this pool. - } - } - } -} +// use afk::types::jediswap_types::{MintParams}; +// use afk::types::launchpad_types::{ +// MINTER_ROLE, ADMIN_ROLE, StoredName, BuyToken, SellToken, CreateToken, LaunchUpdated, +// TokenQuoteBuyCoin, TokenLaunch, SharesTokenUser, BondingType, Token, CreateLaunch, +// SetJediswapNFTRouterV2, SetJediswapV2Factory, SupportedExchanges, LiquidityCreated, +// LiquidityCanBeAdded, MetadataLaunch, TokenClaimed, MetadataCoinAdded, EkuboPoolParameters, +// LaunchParameters, EkuboLP, CallbackData, EkuboLaunchParameters, LaunchCallback, LiquidityType, +// EkuboLiquidityParameters, LiquidityParameters +// }; +// use starknet::ClassHash; +// use starknet::ContractAddress; + +// #[starknet::interface] +// pub trait ILaunchpadMarketplace { +// // User call +// fn create_token( +// ref self: TContractState, +// recipient: ContractAddress, +// symbol: felt252, +// name: felt252, +// initial_supply: u256, +// contract_address_salt: felt252, +// is_unruggable: bool +// ) -> ContractAddress; + +// fn create_and_launch_token( +// ref self: TContractState, +// symbol: felt252, +// name: felt252, +// initial_supply: u256, +// contract_address_salt: felt252, +// is_unruggable: bool +// ) -> ContractAddress; +// fn launch_token(ref self: TContractState, coin_address: ContractAddress); +// fn launch_liquidity(ref self: TContractState, coin_address: ContractAddress); +// // fn buy_coin(ref self: TContractState, coin_address: ContractAddress, amount: u256); +// fn buy_coin_by_quote_amount( +// ref self: TContractState, coin_address: ContractAddress, quote_amount: u256, +// // ekubo_pool_params: Option, +// ); +// fn sell_coin(ref self: TContractState, coin_address: ContractAddress, quote_amount: u256); + +// fn claim_coin_buy(ref self: TContractState, coin_address: ContractAddress, amount: u256); +// fn add_metadata( +// ref self: TContractState, coin_address: ContractAddress, metadata: MetadataLaunch +// ); + +// // Views +// fn get_threshold_liquidity(self: @TContractState) -> u256; +// fn get_default_token(self: @TContractState,) -> TokenQuoteBuyCoin; + +// // Main function to calculate amount +// fn get_amount_by_type_of_coin_or_quote( +// self: @TContractState, +// coin_address: ContractAddress, +// amount: u256, +// is_decreased: bool, +// is_quote_amount: bool +// ) -> u256; +// fn get_coin_amount_by_quote_amount( +// self: @TContractState, coin_address: ContractAddress, quote_amount: u256, is_decreased: bool +// ) -> u256; + +// // fn get_quote_paid_by_amount_coin( +// // self: @TContractState, coin_address: ContractAddress, quote_amount: u256, is_decreased: +// // bool +// // ) -> u256; + +// fn get_coin_launch(self: @TContractState, key_user: ContractAddress,) -> TokenLaunch; +// fn get_share_key_of_user( +// self: @TContractState, owner: ContractAddress, key_user: ContractAddress, +// ) -> SharesTokenUser; +// fn get_all_launch(self: @TContractState) -> Span; + +// fn get_all_coins(self: @TContractState) -> Span; + +// // Admins +// fn set_token(ref self: TContractState, token_quote: TokenQuoteBuyCoin); +// fn set_protocol_fee_percent(ref self: TContractState, protocol_fee_percent: u256); +// fn set_creator_fee_percent(ref self: TContractState, creator_fee_percent: u256); +// fn set_dollar_paid_coin_creation(ref self: TContractState, dollar_price: u256); +// fn set_dollar_paid_launch_creation(ref self: TContractState, dollar_price: u256); +// fn set_dollar_paid_finish_percentage(ref self: TContractState, bps: u256); +// fn set_class_hash(ref self: TContractState, class_hash: ClassHash); +// fn set_protocol_fee_destination( +// ref self: TContractState, protocol_fee_destination: ContractAddress +// ); +// fn set_threshold_liquidity(ref self: TContractState, threshold_liquidity: u256); +// fn set_address_jediswap_factory_v2( +// ref self: TContractState, address_jediswap_factory_v2: ContractAddress +// ); +// fn set_address_jediswap_nft_router_v2( +// ref self: TContractState, address_jediswap_nft_router_v2: ContractAddress +// ); +// fn set_address_ekubo_factory(ref self: TContractState, address_ekubo_factory: ContractAddress); +// fn set_address_ekubo_router(ref self: TContractState, address_ekubo_router: ContractAddress); +// fn set_exchanges_address( +// ref self: TContractState, exchanges: Span<(SupportedExchanges, ContractAddress)> +// ); + +// //TODO +// fn add_liquidity_jediswap(ref self: TContractState, coin_address: ContractAddress,); +// fn add_liquidity_unrug( +// ref self: TContractState, +// coin_address: ContractAddress, +// launch_params: LaunchParameters, +// ekubo_pool_params: EkuboPoolParameters +// ) -> (u64, EkuboLP); + +// fn add_liquidity_unrug_lp( +// ref self: TContractState, +// coin_address: ContractAddress, +// quote_address: ContractAddress, +// lp_supply: u256, +// launch_params: LaunchParameters, +// ekubo_pool_params: EkuboPoolParameters +// ) -> (u64, EkuboLP); + +// fn add_liquidity_ekubo( +// ref self: TContractState, coin_address: ContractAddress, +// // params: EkuboLaunchParameters +// ) -> (u64, EkuboLP); +// // ) -> Span; + +// fn create_unrug_token( +// ref self: TContractState, +// owner: ContractAddress, +// name: felt252, +// symbol: felt252, +// initial_supply: u256, +// contract_address_salt: felt252, +// is_launch_bonding_now: bool +// ) -> ContractAddress; +// } + +// #[starknet::contract] +// pub mod LaunchpadMarketplace { +// use afk::interfaces::factory::{IFactory, IFactoryDispatcher, IFactoryDispatcherTrait}; +// use afk::interfaces::jediswap::{ +// IJediswapFactoryV2, IJediswapFactoryV2Dispatcher, IJediswapFactoryV2DispatcherTrait, +// IJediswapNFTRouterV2, IJediswapNFTRouterV2Dispatcher, IJediswapNFTRouterV2DispatcherTrait, +// }; +// use afk::launchpad::calcul::{ +// calculate_starting_price_launch, calculate_slope, calculate_pricing, +// get_amount_by_type_of_coin_or_quote, get_coin_amount_by_quote_amount +// }; +// use afk::launchpad::errors; +// // use afk::launchpad::helpers::{distribute_team_alloc, check_common_launch_parameters }; +// use afk::launchpad::helpers::{distribute_team_alloc, check_common_launch_parameters}; +// use afk::launchpad::math::PercentageMath; +// use afk::launchpad::utils::{ +// sort_tokens, get_initial_tick_from_starting_price, get_next_tick_bounds, unique_count, +// calculate_aligned_bound_mag +// }; +// use afk::tokens::erc20::{ERC20, IERC20Dispatcher, IERC20DispatcherTrait}; +// use afk::tokens::memecoin::{IMemecoinDispatcher, IMemecoinDispatcherTrait}; +// use afk::utils::{sqrt}; +// use core::num::traits::Zero; +// use ekubo::components::clear::{IClearDispatcher, IClearDispatcherTrait}; + +// use ekubo::components::shared_locker::{call_core_with_callback, consume_callback_data}; +// use ekubo::interfaces::core::{ICoreDispatcher, ICoreDispatcherTrait, ILocker}; +// use ekubo::interfaces::erc20::{ +// IERC20Dispatcher as EKIERC20Dispatcher, IERC20DispatcherTrait as EKIERC20DispatcherTrait +// }; +// use ekubo::interfaces::positions::{IPositions, IPositionsDispatcher, IPositionsDispatcherTrait}; +// use ekubo::interfaces::router::{IRouterDispatcher, IRouterDispatcherTrait}; +// use ekubo::interfaces::token_registry::{ +// ITokenRegistryDispatcher, ITokenRegistryDispatcherTrait, +// }; +// use ekubo::types::bounds::{Bounds}; +// use ekubo::types::keys::PoolKey; +// use ekubo::types::{i129::i129}; + +// use openzeppelin::access::accesscontrol::{AccessControlComponent}; +// use openzeppelin::introspection::src5::SRC5Component; +// use starknet::storage::{ +// StoragePointerReadAccess, StoragePointerWriteAccess, StoragePathEntry, Map +// }; +// use starknet::syscalls::deploy_syscall; +// use starknet::{ +// ContractAddress, get_caller_address, storage_access::StorageBaseAddress, +// contract_address_const, get_block_timestamp, get_contract_address, ClassHash +// }; +// use super::{ +// StoredName, BuyToken, SellToken, CreateToken, LaunchUpdated, SharesTokenUser, MINTER_ROLE, +// ADMIN_ROLE, BondingType, Token, TokenLaunch, TokenQuoteBuyCoin, CreateLaunch, +// SetJediswapNFTRouterV2, SetJediswapV2Factory, SupportedExchanges, MintParams, +// LiquidityCreated, LiquidityCanBeAdded, MetadataLaunch, TokenClaimed, MetadataCoinAdded, +// EkuboPoolParameters, LaunchParameters, EkuboLP, LiquidityType, CallbackData, +// EkuboLaunchParameters, LaunchCallback, EkuboLiquidityParameters, LiquidityParameters +// }; + + +// const MAX_SUPPLY: u256 = 100_000_000; +// const INITIAL_SUPPLY: u256 = MAX_SUPPLY / 5; +// const MAX_STEPS_LOOP: u256 = 100; +// // Total supply / LIQUIDITY_RATIO +// // Get the 20% of Bonding curve going to Liquidity +// // Liquidity can be lock to Unrug +// const LIQUIDITY_RATIO: u256 = 5; // Divid by 5 the total supply. +// // TODO add with a enabled pay boolean to be free at some point +// const PAY_TO_LAUNCH: u256 = 1; // amount in the coin used +// const LIQUIDITY_PERCENTAGE: u256 = 2000; //20% +// const MIN_FEE_PROTOCOL: u256 = 10; //0.1% +// const MAX_FEE_PROTOCOL: u256 = 1000; //10% +// const MID_FEE_PROTOCOL: u256 = 100; //1% + +// const MIN_FEE_CREATOR: u256 = 100; //1% +// const MID_FEE_CREATOR: u256 = 1000; //10% +// const MAX_FEE_CREATOR: u256 = 5000; //50% + +// const BPS: u256 = 10_000; // 100% = 10_000 bps +// const SCALE_FACTOR: u256 = +// 100_000_000_000_000_000; // Scale factor decimals place for price division and others stuff + +// // Unrug params + +// // CHANGE it +// /// The maximum percentage of the total supply that can be allocated to the team. +// /// This is to prevent the team from having too much control over the supply. +// const MAX_SUPPLY_PERCENTAGE_TEAM_ALLOCATION: u16 = 1_000; // 10% + +// /// The maximum number of holders one can specify when launching. +// /// This is to prevent the contract from being is_launched with a large number of holders. +// /// Once reached, transfers are disabled until the memecoin is is_launched. +// const MAX_HOLDERS_LAUNCH: u8 = 10; + +// component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent); +// component!(path: SRC5Component, storage: src5, event: SRC5Event); + +// // AccessControl +// #[abi(embed_v0)] +// impl AccessControlImpl = +// AccessControlComponent::AccessControlImpl; +// impl AccessControlInternalImpl = AccessControlComponent::InternalImpl; + +// // SRC5 +// #[abi(embed_v0)] +// impl SRC5Impl = SRC5Component::SRC5Impl; + +// #[storage] +// struct Storage { +// // Admin & others contract +// coin_class_hash: ClassHash, +// quote_tokens: Map::, +// exchange_configs: Map, +// quote_token: ContractAddress, +// protocol_fee_destination: ContractAddress, +// address_jediswap_factory_v2: ContractAddress, +// address_jediswap_nft_router_v2: ContractAddress, +// address_ekubo_factory: ContractAddress, +// address_ekubo_router: ContractAddress, +// // User states +// token_created: Map::, +// launched_coins: Map::, +// metadata_coins: Map::, +// shares_by_users: Map::<(ContractAddress, ContractAddress), SharesTokenUser>, +// bonding_type: Map::, +// array_launched_coins: Map::, +// array_coins: Map::, +// tokens_created: Map::, +// launch_created: Map::, +// // Parameters +// is_tokens_buy_enable: Map::, +// default_token: TokenQuoteBuyCoin, +// dollar_price_launch_pool: u256, +// dollar_price_create_token: u256, +// dollar_price_percentage: u256, +// starting_price: u256, +// threshold_liquidity: u256, +// threshold_market_cap: u256, +// liquidity_raised_amount_in_dollar: u256, +// protocol_fee_percent: u256, +// creator_fee_percent: u256, +// is_fees_protocol: bool, +// step_increase_linear: u256, +// is_custom_launch_enable: bool, +// is_custom_token_enable: bool, +// is_paid_launch_enable: bool, +// is_create_token_paid: bool, +// // Stats +// total_keys: u64, +// total_token: u64, +// total_launch: u64, +// total_shares_keys: u64, +// // External contract +// factory_address: ContractAddress, +// ekubo_registry: ContractAddress, +// core: ContractAddress, +// positions: ContractAddress, +// ekubo_exchange_address: ContractAddress, +// #[substorage(v0)] +// accesscontrol: AccessControlComponent::Storage, +// #[substorage(v0)] +// src5: SRC5Component::Storage, +// } + +// #[event] +// #[derive(Drop, starknet::Event)] +// pub enum Event { +// StoredName: StoredName, +// BuyToken: BuyToken, +// SellToken: SellToken, +// CreateToken: CreateToken, +// LaunchUpdated: LaunchUpdated, +// CreateLaunch: CreateLaunch, +// SetJediswapV2Factory: SetJediswapV2Factory, +// SetJediswapNFTRouterV2: SetJediswapNFTRouterV2, +// LiquidityCreated: LiquidityCreated, +// LiquidityCanBeAdded: LiquidityCanBeAdded, +// TokenClaimed: TokenClaimed, +// MetadataCoinAdded: MetadataCoinAdded, +// #[flat] +// AccessControlEvent: AccessControlComponent::Event, +// #[flat] +// SRC5Event: SRC5Component::Event, +// } + +// #[constructor] +// fn constructor( +// ref self: ContractState, +// admin: ContractAddress, +// starting_price: u256, +// token_address: ContractAddress, +// step_increase_linear: u256, +// coin_class_hash: ClassHash, +// threshold_liquidity: u256, +// threshold_market_cap: u256, +// factory_address: ContractAddress, +// ekubo_registry: ContractAddress, +// core: ContractAddress, +// positions: ContractAddress, +// ekubo_exchange_address: ContractAddress +// ) { +// self.coin_class_hash.write(coin_class_hash); +// // AccessControl-related initialization +// self.accesscontrol.initializer(); +// self.accesscontrol._grant_role(MINTER_ROLE, admin); +// self.accesscontrol._grant_role(ADMIN_ROLE, admin); + +// let init_token = TokenQuoteBuyCoin { +// token_address: token_address, +// starting_price, +// price: starting_price, +// is_enable: true, +// step_increase_linear +// }; +// self.is_custom_launch_enable.write(false); +// self.is_custom_token_enable.write(false); +// self.default_token.write(init_token.clone()); +// self.starting_price.write(init_token.starting_price); + +// self.threshold_liquidity.write(threshold_liquidity); +// self.threshold_market_cap.write(threshold_market_cap); +// self.protocol_fee_destination.write(admin); +// self.step_increase_linear.write(step_increase_linear); +// self.total_keys.write(0); +// self.total_token.write(0); +// self.total_launch.write(0); +// self.protocol_fee_percent.write(MID_FEE_PROTOCOL); +// self.creator_fee_percent.write(MIN_FEE_CREATOR); +// self.factory_address.write(factory_address); +// // self.ekubo_registry.write(ekubo_registry); +// self.core.write(core); +// self.positions.write(positions); +// self.ekubo_exchange_address.write(ekubo_exchange_address); +// } + +// // Public functions inside an impl block +// #[abi(embed_v0)] +// impl LaunchpadMarketplace of super::ILaunchpadMarketplace { +// // ADMIN + +// fn set_token(ref self: ContractState, token_quote: TokenQuoteBuyCoin) { +// self.accesscontrol.assert_only_role(ADMIN_ROLE); +// self.is_tokens_buy_enable.entry(token_quote.token_address).write(token_quote); +// } + +// fn set_protocol_fee_percent(ref self: ContractState, protocol_fee_percent: u256) { +// assert(protocol_fee_percent < MAX_FEE_PROTOCOL, 'protocol_fee_too_high'); +// assert(protocol_fee_percent > MIN_FEE_PROTOCOL, 'protocol_fee_too_low'); + +// self.accesscontrol.assert_only_role(ADMIN_ROLE); +// self.protocol_fee_percent.write(protocol_fee_percent); +// } + +// fn set_protocol_fee_destination( +// ref self: ContractState, protocol_fee_destination: ContractAddress +// ) { +// self.accesscontrol.assert_only_role(ADMIN_ROLE); +// self.protocol_fee_destination.write(protocol_fee_destination); +// } + +// fn set_creator_fee_percent(ref self: ContractState, creator_fee_percent: u256) { +// self.accesscontrol.assert_only_role(ADMIN_ROLE); +// assert(creator_fee_percent < MAX_FEE_CREATOR, 'creator_fee_too_high'); +// assert(creator_fee_percent > MIN_FEE_CREATOR, 'creator_fee_too_low'); +// self.creator_fee_percent.write(creator_fee_percent); +// } + +// fn set_dollar_paid_coin_creation(ref self: ContractState, dollar_price: u256) { +// self.accesscontrol.assert_only_role(ADMIN_ROLE); +// self.dollar_price_create_token.write(dollar_price); +// } + +// fn set_dollar_paid_launch_creation(ref self: ContractState, dollar_price: u256) { +// self.accesscontrol.assert_only_role(ADMIN_ROLE); +// self.dollar_price_launch_pool.write(dollar_price); +// } + +// fn set_dollar_paid_finish_percentage(ref self: ContractState, bps: u256) { +// self.accesscontrol.assert_only_role(ADMIN_ROLE); +// self.dollar_price_percentage.write(bps); +// } + +// // Set threshold liquidity +// fn set_threshold_liquidity(ref self: ContractState, threshold_liquidity: u256) { +// self.accesscontrol.assert_only_role(ADMIN_ROLE); +// self.threshold_liquidity.write(threshold_liquidity); +// } + +// // Jediwswap factory address +// fn set_address_jediswap_factory_v2( +// ref self: ContractState, address_jediswap_factory_v2: ContractAddress +// ) { +// self.accesscontrol.assert_only_role(ADMIN_ROLE); +// // self.ownable.assert_only_owner(); +// self.address_jediswap_factory_v2.write(address_jediswap_factory_v2); +// self +// .emit( +// SetJediswapV2Factory { +// address_jediswap_factory_v2: address_jediswap_factory_v2 +// } +// ); +// } + +// fn set_address_jediswap_nft_router_v2( +// ref self: ContractState, address_jediswap_nft_router_v2: ContractAddress +// ) { +// self.accesscontrol.assert_only_role(ADMIN_ROLE); +// self.address_jediswap_nft_router_v2.write(address_jediswap_nft_router_v2); +// self +// .emit( +// SetJediswapNFTRouterV2 { +// address_jediswap_nft_router_v2: address_jediswap_nft_router_v2 +// } +// ); +// } + +// fn set_address_ekubo_factory( +// ref self: ContractState, address_ekubo_factory: ContractAddress +// ) { +// self.accesscontrol.assert_only_role(ADMIN_ROLE); +// self.address_ekubo_factory.write(address_ekubo_factory); +// // Optionally emit an event +// } + +// fn set_address_ekubo_router( +// ref self: ContractState, address_ekubo_router: ContractAddress +// ) { +// self.accesscontrol.assert_only_role(ADMIN_ROLE); +// self.address_ekubo_router.write(address_ekubo_router); +// // Optionally emit an event +// } + +// fn set_exchanges_address( +// ref self: ContractState, exchanges: Span<(SupportedExchanges, ContractAddress)> +// ) { +// self.accesscontrol.assert_only_role(ADMIN_ROLE); +// let mut dex = exchanges; +// // Add Exchanges configurations +// loop { +// match dex.pop_front() { +// Option::Some((exchange, address)) => self +// .exchange_configs +// .entry(*exchange) +// .write(*address), +// Option::None => { break; } +// } +// }; +// } + + +// fn set_class_hash(ref self: ContractState, class_hash: ClassHash) { +// self.accesscontrol.assert_only_role(ADMIN_ROLE); +// self.coin_class_hash.write(class_hash); +// } +// // User call + +// // Create keys for an user +// fn create_token( +// ref self: ContractState, +// recipient: ContractAddress, +// symbol: felt252, +// name: felt252, +// initial_supply: u256, +// contract_address_salt: felt252, +// is_unruggable: bool +// ) -> ContractAddress { +// let caller = get_caller_address(); +// let token_address = self +// ._create_token( +// recipient, +// caller, +// symbol, +// name, +// initial_supply, +// contract_address_salt, +// is_unruggable +// ); + +// token_address +// } + +// // Creat coin and launch +// // recipient, caller, symbol, name, initial_supply, contract_address_salt +// fn create_and_launch_token( +// ref self: ContractState, +// symbol: felt252, +// name: felt252, +// initial_supply: u256, +// contract_address_salt: felt252, +// is_unruggable: bool +// ) -> ContractAddress { +// let contract_address = get_contract_address(); +// let caller = get_caller_address(); +// let token_address = self +// ._create_token( +// contract_address, +// caller, +// symbol, +// name, +// initial_supply, +// contract_address_salt, +// is_unruggable +// ); +// let contract_address = get_contract_address(); +// self._launch_token(token_address, caller, contract_address, false); +// token_address +// } + +// // Launch coin to pool bonding curve +// fn launch_token(ref self: ContractState, coin_address: ContractAddress) { +// let caller = get_caller_address(); +// let contract_address = get_contract_address(); + +// let token = self.token_created.read(coin_address); +// let is_unruggable = token.is_unruggable; +// self._launch_token(coin_address, caller, contract_address, is_unruggable); +// } + +// // Buy coin by quote amount +// // Get amount of coin receive based on token IN +// fn buy_coin_by_quote_amount( +// ref self: ContractState, coin_address: ContractAddress, quote_amount: u256, +// // ekubo_pool_params: Option +// ) { +// // assert!(quote_amount > 0, "amount == 0"); +// let caller = get_caller_address(); +// let old_launch = self.launched_coins.read(coin_address); +// assert!(!old_launch.owner.is_zero(), "coin not found"); +// let memecoin = IERC20Dispatcher { contract_address: coin_address }; +// let mut pool_coin = old_launch.clone(); +// let total_supply_memecoin = memecoin.total_supply(); +// // let threshold_liquidity = self.threshold_liquidity.read(); +// let threshold_liquidity = pool_coin.threshold_liquidity.clone(); + +// //new liquidity after purchase +// let new_liquidity = pool_coin.liquidity_raised + quote_amount; + +// //assertion +// assert(new_liquidity <= threshold_liquidity, 'threshold liquidity exceeded'); + +// // TODO erc20 token transfer +// let token_quote = old_launch.token_quote.clone(); +// let quote_token_address = token_quote.token_address.clone(); +// let erc20 = IERC20Dispatcher { contract_address: quote_token_address }; +// let protocol_fee_percent = self.protocol_fee_percent.read(); + +// // IF AMOUNT COIN TO HAVE => GET AMOUNT QUOTE TO PAID +// let mut total_price = quote_amount.clone(); +// let old_price = pool_coin.price.clone(); +// let mut amount_protocol_fee: u256 = total_price * protocol_fee_percent / BPS; +// let mut remain_liquidity = total_price - amount_protocol_fee; +// // let mut amount = 0; +// // Pay with quote token +// // Transfer quote & coin +// // TOdo fix issue price +// let mut amount = get_amount_by_type_of_coin_or_quote( +// pool_coin.clone(), coin_address.clone(), remain_liquidity.clone(), false, true +// ); +// // remain_liquidity = total_price - amount_protocol_fee; +// // TODO check available to buy + +// // println!("amount receive {:?}", amount); + +// assert(amount <= pool_coin.available_supply, 'no available supply'); + +// erc20 +// .transfer_from( +// get_caller_address(), self.protocol_fee_destination.read(), amount_protocol_fee +// ); +// // println!("remain_liquidity {:?}", remain_liquidity); +// erc20.transfer_from(get_caller_address(), get_contract_address(), remain_liquidity); +// // In case the user want to buy more than the threshold +// // Give the available supply +// // if total_price + old_launch.liquidity_raised.clone() > threshold_liquidity { +// // total_price = threshold_liquidity - old_launch.liquidity_raised.clone(); +// // amount = pool_coin.available_supply; + +// // amount_protocol_fee = total_price * protocol_fee_percent / BPS; +// // // remain_liquidity = total_price - amount_protocol_fee; +// // remain_liquidity = total_price; +// // erc20 +// // .transfer_from( +// // get_caller_address(), +// // self.protocol_fee_destination.read(), +// // amount_protocol_fee +// // ); +// // // println!("remain_liquidity {:?}", remain_liquidity); +// // erc20.transfer_from(get_caller_address(), get_contract_address(), +// // remain_liquidity); +// // } else { +// // amount = self +// // ._get_amount_by_type_of_coin_or_quote(coin_address, total_price, false, +// // true); +// // // remain_liquidity = total_price - amount_protocol_fee; + +// // erc20 +// // .transfer_from( +// // get_caller_address(), +// // self.protocol_fee_destination.read(), +// // amount_protocol_fee +// // ); +// // // println!("remain_liquidity {:?}", remain_liquidity); +// // erc20.transfer_from(get_caller_address(), get_contract_address(), +// // remain_liquidity); +// // } + +// // Assertion: Amount Received Validation +// // Optionally, re-calculate the quote amount based on the amount to ensure consistency +// // println!("total_price {:?}", total_price); +// // Change the Stats of pool: +// // Liquidity raised +// // Available supply +// // Token holded + +// pool_coin.liquidity_raised += remain_liquidity; +// pool_coin.total_token_holded += amount; +// pool_coin.price = total_price; + +// if amount >= pool_coin.available_supply { +// pool_coin.available_supply = 0; +// } else { +// pool_coin.available_supply -= amount; +// } + +// // Update share and coin stats for an user +// let mut old_share = self.shares_by_users.read((get_caller_address(), coin_address)); + +// let mut share_user = old_share.clone(); +// if old_share.owner.is_zero() { +// share_user = +// SharesTokenUser { +// owner: get_caller_address(), +// token_address: coin_address, +// amount_owned: amount, +// amount_buy: amount, +// amount_sell: 0, +// created_at: get_block_timestamp(), +// total_paid: total_price, +// }; +// let total_key_share = self.total_shares_keys.read(); +// self.total_shares_keys.write(total_key_share + 1); +// } else { +// share_user.total_paid += total_price; +// share_user.amount_owned += amount; +// share_user.amount_buy += amount; +// } +// // pool_coin.price = total_price / amount; + +// // Check if liquidity threshold raise +// let threshold = self.threshold_liquidity.read(); +// let threshold_mc = self.threshold_market_cap.read(); +// // println!("threshold {:?}", threshold); +// // println!("pool_coin.liquidity_raised {:?}", pool_coin.liquidity_raised); + +// let mc = (pool_coin.price * total_supply_memecoin); +// // TODO add liquidity launch +// // TOTAL_SUPPLY / 5 +// // 20% go the liquidity +// // 80% bought by others + +// // TODO check reetrancy guard +// // Update state +// self +// .shares_by_users +// .entry((get_caller_address(), coin_address)) +// .write(share_user.clone()); +// self.launched_coins.entry(coin_address).write(pool_coin.clone()); + +// // TODO finish test and fix +// // Fix price of the last +// if pool_coin.liquidity_raised >= threshold { +// self +// .emit( +// LiquidityCanBeAdded { +// pool: pool_coin.token_address.clone(), +// asset: pool_coin.token_address.clone(), +// quote_token_address: pool_coin.token_quote.token_address.clone(), +// } +// ); +// // self._add_liquidity(coin_address, SupportedExchanges::Jediswap); +// // self._add_liquidity(coin_address, SupportedExchanges::Ekubo); +// // TODO fix add liquidity ekubo +// // self._add_liquidity_ekubo(coin_address); +// } + +// self +// .emit( +// BuyToken { +// caller: get_caller_address(), +// token_address: coin_address, +// amount: amount, +// price: total_price, +// protocol_fee: amount_protocol_fee, +// // creator_fee: 0, +// last_price: old_price, +// timestamp: get_block_timestamp(), +// quote_amount: quote_amount +// } +// ); +// } + + +// // TODO finish and fix +// fn sell_coin(ref self: ContractState, coin_address: ContractAddress, quote_amount: u256) { +// let old_pool = self.launched_coins.read(coin_address); +// assert(!old_pool.owner.is_zero(), 'coin not found'); + +// let caller = get_caller_address(); +// let mut old_share = self.shares_by_users.read((get_caller_address(), coin_address)); + +// let mut share_user = old_share.clone(); + +// // TODO erc20 token transfer +// let total_supply = old_pool.total_supply; +// let token_quote = old_pool.token_quote.clone(); +// let quote_token_address = token_quote.token_address.clone(); +// assert(old_pool.liquidity_raised >= quote_amount, 'liquidity <= amount'); +// assert(old_pool.is_liquidity_launch == false, 'token tradeable'); + +// // TODO fix this function +// // let mut amount = self +// // ._get_coin_amount_by_quote_amount(coin_address, quote_amount, true); + +// // Todo check user amount fee creator if needed +// let creator_fee_percent = self.creator_fee_percent.read(); +// let protocol_fee_percent = self.protocol_fee_percent.read(); + +// let amount_protocol_fee: u256 = quote_amount * protocol_fee_percent / BPS; +// let amount_creator_fee = quote_amount * creator_fee_percent / BPS; +// let remain_liquidity = quote_amount - amount_protocol_fee; +// // let amount_to_user: u256 = quote_amount - amount_protocol_fee - amount_creator_fee; + +// let mut amount = get_amount_by_type_of_coin_or_quote( +// old_pool.clone(), coin_address.clone(), remain_liquidity.clone(), false, true +// ); + +// // Verify Amount owned +// assert(old_pool.total_supply >= quote_amount, 'above supply'); +// assert(share_user.amount_owned >= amount, 'above supply'); + +// // let mut total_price = amount; +// // println!("amount {:?}", amount); +// // println!("quote_amount {:?}", quote_amount); +// // println!("total_price {:?}", total_price); +// let erc20 = IERC20Dispatcher { contract_address: quote_token_address }; + +// // Ensure fee percentages are within valid bounds +// assert( +// protocol_fee_percent <= MAX_FEE_PROTOCOL +// && protocol_fee_percent >= MIN_FEE_PROTOCOL, +// 'protocol fee out' +// ); +// // assert( +// // creator_fee_percent <= MAX_FEE_CREATOR && creator_fee_percent >= MIN_FEE_CREATOR, +// // 'creator_fee out' +// // ); + +// // assert!(old_share.amount_owned >= amount, "share to sell > supply"); +// // println!("amount{:?}", amount); +// // assert!(total_supply >= quote_amount, "share to sell > supply"); +// // assert( old_pool.liquidity_raised >= quote_amount, 'liquidity_raised <= amount'); + +// let old_price = old_pool.price.clone(); +// let total_price = old_pool.price.clone(); +// // Update keys with new values +// let mut pool_update = old_pool.clone(); + +// // let remain_liquidity = total_price ; +// assert(old_pool.liquidity_raised >= remain_liquidity, 'liquidity <= amount'); + +// // Ensure fee calculations are correct +// // assert( +// // amount_to_user + amount_protocol_fee + amount_creator_fee == quote_amount, +// // 'fee calculation mismatch' +// // ); + +// // Assertion: Check if the contract has enough quote tokens to transfer +// let contract_quote_balance = erc20.balance_of(get_contract_address()); +// assert!( +// contract_quote_balance >= quote_amount, +// "contract has insufficient quote token balance" +// ); + +// // Transfer protocol fee to the designated destination +// if amount_protocol_fee > 0 { +// erc20.transfer(self.protocol_fee_destination.read(), amount_protocol_fee); +// } + +// // Transfer the remaining quote amount to the user +// if remain_liquidity > 0 { +// erc20.transfer(caller, remain_liquidity); +// } + +// // Assertion: Ensure the user receives the correct amount +// let user_received = erc20.balance_of(caller); +// assert(user_received >= remain_liquidity, 'user not receive amount'); + +// // TODO sell coin if it's already sendable and transferable +// // ENABLE if direct launch coin +// // let memecoin = IERC20Dispatcher { contract_address: coin_address }; +// // memecoin.transfer_from(get_caller_address(), get_contract_address(), amount); + +// // TODO fix amount owned and sellable. +// // Update share user coin +// share_user.amount_owned -= amount; +// share_user.amount_sell += amount; + +// // TODO check reetrancy guard + +// // Assertion: Ensure pool liquidity remains consistent +// assert!( +// old_pool.liquidity_raised >= quote_amount, "pool liquidity inconsistency after sale" +// ); + +// // TODO finish update state +// // pool_update.price = total_price; +// pool_update.liquidity_raised -= remain_liquidity; +// pool_update.total_token_holded -= amount; +// pool_update.available_supply += amount; + +// // Assertion: Ensure the pool's liquidity and token holded are updated correctly +// // assert!( +// // pool_update.liquidity_raised + quote_amount == old_pool.liquidity_raised, +// // "liquidity_raised mismatch after update" +// // ); +// // assert!( +// // pool_update.total_token_holded +// // + self +// // ._get_coin_amount_by_quote_amount( +// // coin_address, quote_amount, true +// // ) == old_pool +// // .total_token_holded, +// // "total_token_holded mismatch after update" +// // ); + +// self +// .shares_by_users +// .entry((get_caller_address(), coin_address.clone())) +// .write(share_user.clone()); +// self.launched_coins.entry(coin_address.clone()).write(pool_update.clone()); +// self +// .emit( +// SellToken { +// caller: caller, +// key_user: coin_address, +// amount: quote_amount, +// price: total_price, // Adjust if necessary +// protocol_fee: amount_protocol_fee, +// creator_fee: amount_creator_fee, +// timestamp: get_block_timestamp(), +// last_price: old_pool.price, +// } +// ); +// } + + +// // TODO finish check +// // Launch liquidity if threshold ok +// // Add more exchanges. Start with EKUBO by default +// fn launch_liquidity( +// ref self: ContractState, coin_address: ContractAddress, // exchange:SupportedExchanges +// ) { +// // TODO auto distrib and claim? + +// let caller = get_caller_address(); + +// let pool = self.launched_coins.read(coin_address); + +// assert(caller == pool.owner, errors::OWNER_DIFFERENT); + +// self._add_liquidity_ekubo(coin_address); +// // self._add_liquidity(coin_address, SupportedExchanges::Jediswap, ekubo_pool_params); +// // self._add_liquidity(coin_address, SupportedExchanges::Ekubo, ekubo_pool_params); +// } +// fn add_liquidity_jediswap(ref self: ContractState, coin_address: ContractAddress) { +// // TODO auto distrib and claim? +// let caller = get_caller_address(); + +// let pool = self.launched_coins.read(coin_address); + +// assert(caller == pool.owner, errors::OWNER_DIFFERENT); + +// self._add_liquidity_jediswap(coin_address); +// // self._add_liquidity(coin_address, SupportedExchanges::Jediswap, ekubo_pool_params); +// // self._add_liquidity(coin_address, SupportedExchanges::Ekubo, ekubo_pool_params); +// } + + +// // TODO Finish this function +// // Claim coin if liquidity is sent +// // Check and modify the share of user +// fn claim_coin_buy(ref self: ContractState, coin_address: ContractAddress, amount: u256) { +// let caller = get_contract_address(); +// // Verify if liquidity launch +// let mut launch = self.launched_coins.read(coin_address); +// assert(launch.is_liquidity_launch == true, 'not launch yet'); + +// // Verify share of user +// let mut share_user = self.shares_by_users.read((get_caller_address(), coin_address)); + +// let max_amount_claimable = share_user.amount_owned; +// assert(max_amount_claimable >= amount, 'share below'); + +// // Transfer memecoin +// let memecoin = IERC20Dispatcher { contract_address: coin_address }; +// memecoin.transfer(caller, amount); + +// // Update new share and emit event +// share_user.amount_owned -= amount; +// self.shares_by_users.entry((get_caller_address(), coin_address)).write(share_user); + +// self +// .emit( +// TokenClaimed { +// token_address: coin_address, +// owner: caller, +// timestamp: get_block_timestamp(), +// amount, +// } +// ); +// } + +// // TODO finish add Metadata +// fn add_metadata( +// ref self: ContractState, coin_address: ContractAddress, metadata: MetadataLaunch +// ) { +// let caller = get_contract_address(); +// // Verify if caller is owner +// let mut launch = self.launched_coins.read(coin_address); +// assert(launch.owner == caller, 'not owner'); + +// // Add or update metadata + +// self.metadata_coins.entry(coin_address).write(metadata.clone()); +// self +// .emit( +// MetadataCoinAdded { +// token_address: coin_address, +// url: metadata.url, +// timestamp: get_block_timestamp(), +// nostr_event_id: metadata.nostr_event_id, +// } +// ); +// } + + +// fn get_default_token(self: @ContractState) -> TokenQuoteBuyCoin { +// self.default_token.read() +// } + +// fn get_threshold_liquidity(self: @ContractState) -> u256 { +// self.threshold_liquidity.read() +// } + + +// fn get_coin_launch(self: @ContractState, key_user: ContractAddress,) -> TokenLaunch { +// self.launched_coins.read(key_user) +// } + +// fn get_share_key_of_user( +// self: @ContractState, owner: ContractAddress, key_user: ContractAddress, +// ) -> SharesTokenUser { +// self.shares_by_users.read((owner, key_user)) +// } + +// fn get_all_coins(self: @ContractState) -> Span { +// let max_coin_id = self.total_token.read() + 1; +// let mut coins: Array = ArrayTrait::new(); +// let mut i = 0; //Since the stream id starts from 0 +// loop { +// if i >= max_coin_id {} +// let coin = self.array_coins.read(i); +// if coin.owner.is_zero() { +// break coins.span(); +// } +// coins.append(coin); +// i += 1; +// } +// } + +// fn get_all_launch(self: @ContractState) -> Span { +// let max_key_id = self.total_launch.read() + 1; +// let mut launches: Array = ArrayTrait::new(); +// let mut i = 0; //Since the stream id starts from 0 +// loop { +// if i >= max_key_id {} +// let pool = self.array_launched_coins.read(i); +// if pool.owner.is_zero() { +// break launches.span(); +// } +// launches.append(pool); +// i += 1; +// } +// } + +// // The function calculates the amiunt of quote_token you need to buy a coin in the pool +// fn get_amount_by_type_of_coin_or_quote( +// self: @ContractState, +// coin_address: ContractAddress, +// amount: u256, +// is_decreased: bool, +// is_quote_amount: bool +// ) -> u256 { +// let pool = self.launched_coins.read(coin_address).clone(); +// get_amount_by_type_of_coin_or_quote( +// pool.clone(), coin_address, amount, is_decreased, is_quote_amount +// ) +// // self +// // .get_amount_by_type_of_coin_or_quote( +// // coin_address, amount, is_decreased, is_quote_amount +// // ) +// } + +// fn get_coin_amount_by_quote_amount( +// self: @ContractState, +// coin_address: ContractAddress, +// quote_amount: u256, +// is_decreased: bool +// ) -> u256 { +// let pool = self.launched_coins.read(coin_address).clone(); + +// // self._get_coin_amount_by_quote_amount(coin_address, quote_amount, is_decreased) +// get_coin_amount_by_quote_amount(pool.clone(), quote_amount, is_decreased) +// } + +// // fn get_quote_paid_by_amount_coin( +// // self: @ContractState, +// // coin_address: ContractAddress, +// // quote_amount: u256, +// // is_decreased: bool +// // ) -> u256 { +// // self._get_quote_paid_by_amount_coin(coin_address, quote_amount, is_decreased) +// // } + +// //TODO refac +// fn add_liquidity_unrug( +// ref self: ContractState, +// coin_address: ContractAddress, +// launch_params: LaunchParameters, +// ekubo_pool_params: EkuboPoolParameters +// ) -> (u64, EkuboLP) { +// //TODO restrict fn? + +// self._add_internal_liquidity_unrug(coin_address, launch_params, ekubo_pool_params) +// // INTEGRATION not working +// // self._add_liquidity_unrug(launch_params, ekubo_pool_params) +// } + +// //TODO refac +// fn add_liquidity_unrug_lp( +// ref self: ContractState, +// coin_address: ContractAddress, +// quote_address: ContractAddress, +// lp_supply: u256, +// launch_params: LaunchParameters, +// ekubo_pool_params: EkuboPoolParameters +// ) -> (u64, EkuboLP) { +// //TODO restrict fn? + +// let caller = get_caller_address(); +// self +// ._add_internal_liquidity_unrug_lp( +// caller, coin_address, quote_address, lp_supply, launch_params, ekubo_pool_params +// ) +// // INTEGRATION not working +// // self._add_liquidity_unrug(launch_params, ekubo_pool_params) +// } + +// fn create_unrug_token( +// ref self: ContractState, +// owner: ContractAddress, +// name: felt252, +// symbol: felt252, +// initial_supply: u256, +// contract_address_salt: felt252, +// is_launch_bonding_now: bool, +// ) -> ContractAddress { +// let caller = get_caller_address(); +// let creator = get_caller_address(); +// let contract_address = get_contract_address(); +// let owner = get_caller_address(); +// if is_launch_bonding_now == true { +// let token_address = self +// ._create_token( +// contract_address, +// caller, +// symbol, +// name, +// initial_supply, +// contract_address_salt, +// true +// ); +// self._launch_token(token_address, caller, contract_address, true); +// token_address +// } else { +// let token_address = self +// ._create_token( +// contract_address, +// caller, +// symbol, +// name, +// initial_supply, +// contract_address_salt, +// true +// ); +// let contract_address = get_contract_address(); + +// let mut token = Token { +// token_address: token_address, +// owner: owner, +// creator: creator, +// name, +// symbol, +// total_supply: initial_supply, +// initial_supply: initial_supply, +// created_at: get_block_timestamp(), +// token_type: Option::None, +// is_unruggable: true +// }; +// self.token_created.entry(token_address).write(token); +// token_address +// } +// } + +// fn add_liquidity_ekubo( +// ref self: ContractState, coin_address: ContractAddress, +// // params: EkuboLaunchParameters +// // ) -> Span { +// ) -> (u64, EkuboLP) { +// let caller = get_caller_address(); +// let pool = self.launched_coins.read(coin_address); +// assert(caller == pool.owner, errors::OWNER_DIFFERENT); +// self._add_liquidity_ekubo(coin_address) +// } +// } + +// #[external(v0)] +// impl LockerImpl of ILocker { +// /// Callback function called by the core contract. +// fn locked(ref self: ContractState, id: u32, data: Span) -> Span { +// let core_address = self.core.read(); +// let core = ICoreDispatcher { contract_address: core_address }; +// // Register the token in Ekubo Registry +// let registry_address = self.ekubo_registry.read(); +// // println!("IN HERE: {}", 1); +// let dex_address = self.core.read(); +// let ekubo_core_address = self.core.read(); +// let ekubo_exchange_address = self.ekubo_exchange_address.read(); +// let positions_address = self.positions.read(); + +// match consume_callback_data::(core, data) { +// CallbackData::LaunchCallback(params) => { +// let launch_params: EkuboLaunchParameters = params.params; +// let (token0, token1) = sort_tokens( +// launch_params.token_address, launch_params.quote_address +// ); +// let memecoin = EKIERC20Dispatcher { +// contract_address: launch_params.token_address +// }; +// let base_token = EKIERC20Dispatcher { +// contract_address: launch_params.quote_address +// }; +// let registry = ITokenRegistryDispatcher { contract_address: registry_address }; +// // println!("IN HERE: {}", 2); + +// let pool_key = PoolKey { +// token0: token0, +// token1: token1, +// fee: launch_params.pool_params.fee, +// tick_spacing: launch_params.pool_params.tick_spacing, +// extension: 0.try_into().unwrap(), +// }; + +// let lp_supply = launch_params.lp_supply.clone(); +// // println!("IN HERE: {}", 3); + +// // The initial_tick must correspond to the wanted initial price in quote/MEME +// // The ekubo prices are always in TOKEN1/TOKEN0. +// // The initial_tick is the lower bound if the quote is token1, the upper bound +// // otherwise. +// let is_token1_quote = launch_params.quote_address == token1; +// let (initial_tick, full_range_bounds) = get_initial_tick_from_starting_price( +// launch_params.pool_params.starting_price, +// launch_params.pool_params.bound, +// is_token1_quote +// ); + +// let pool = self.launched_coins.read(launch_params.token_address); + +// // println!("IN HERE: {}", 4); + +// base_token.approve(registry.contract_address, pool.liquidity_raised); +// base_token.approve(ekubo_core_address, pool.liquidity_raised); +// base_token.approve(positions_address, lp_supply); + +// memecoin.approve(registry.contract_address, lp_supply); +// memecoin.approve(positions_address, lp_supply); +// memecoin.approve(dex_address, lp_supply); +// memecoin.approve(ekubo_core_address, lp_supply); +// // memecoin.transfer(registry.contract_address, 1000000000000000000); +// // memecoin.transfer(registry.contract_address, pool.available_supply); +// // memecoin.transfer(registry.contract_address, pool.available_supply); +// // println!("transfer before register"); +// registry +// .register_token( +// EKIERC20Dispatcher { contract_address: launch_params.token_address } +// ); + +// // println!("initial tick {:?}", initial_tick); +// // Initialize the pool at the initial tick. +// // println!("init pool"); + +// core.maybe_initialize_pool(:pool_key, :initial_tick); +// // println!("init pool"); + +// // println!("IN HERE: {}", 5); +// // println!("supply liq"); + +// // 2. Provide the liquidity to actually initialize the public pool with +// // The pool bounds must be set according to the tick spacing. +// // The bounds were previously computed to provide yield covering the entire +// // interval [lower_bound, starting_price] or [starting_price, upper_bound] +// // depending on the quote. +// let id = self +// ._supply_liquidity_ekubo( +// pool_key, +// launch_params.token_address, +// launch_params.lp_supply, +// full_range_bounds +// ); + +// // println!("IN HERE: {}", 6); + +// let position = EkuboLP { +// // let position = @EkuboLP { +// owner: launch_params.owner, +// quote_address: launch_params.quote_address, +// pool_key, +// bounds: full_range_bounds +// }; +// // println!("position owner {:?}", owner); +// // println!("position quote_address {:?}", quote_address); + +// // At this point, the pool is composed by: +// // n% of liquidity at precise starting tick, reserved for the team to buy +// // the rest of the liquidity, in bounds [starting_price, +inf]; + +// let mut return_data: Array = Default::default(); +// Serde::serialize(@id, ref return_data); +// Serde::serialize( +// @EkuboLP { +// owner: launch_params.owner, +// quote_address: launch_params.quote_address, +// pool_key, +// bounds: full_range_bounds +// }, +// ref return_data +// ); +// return_data.span() +// } +// // CallbackData::WithdrawFeesCallback(params) => { +// // let WithdrawFeesCallback{id, liquidity_type, recipient } = params; +// // let positions = self.positions.read(); +// // let EkuboLP{owner, quote_address: _, pool_key, bounds } = liquidity_type; +// // let pool_key = PoolKey { +// // token0: pool_key.token0, +// // token1: pool_key.token1, +// // fee: pool_key.fee, +// // tick_spacing: pool_key.tick_spacing, +// // extension: pool_key.extension, +// // }; +// // let bounds = Bounds { lower: bounds.lower, upper: bounds.upper, }; +// // positions.collect_fees(id, pool_key, bounds); + +// // // Transfer to recipient is done after the callback +// // let mut return_data = Default::default(); +// // Serde::serialize(@pool_key.token0, ref return_data); +// // Serde::serialize(@pool_key.token1, ref return_data); +// // return_data +// // }, +// } +// } +// } + +// // // Could be a group of functions about a same topic +// #[generate_trait] +// impl InternalFunctions of InternalFunctionsTrait { +// fn _create_token( +// ref self: ContractState, +// recipient: ContractAddress, +// owner: ContractAddress, +// symbol: felt252, +// name: felt252, +// initial_supply: u256, +// contract_address_salt: felt252, +// is_unruggable: bool +// ) -> ContractAddress { +// let mut calldata = array![name.into(), symbol.into()]; +// Serde::serialize(@initial_supply, ref calldata); +// Serde::serialize(@recipient, ref calldata); +// Serde::serialize(@18, ref calldata); + +// let (token_address, _) = deploy_syscall( +// self.coin_class_hash.read(), contract_address_salt, calldata.span(), false +// ) +// .unwrap(); +// // .unwrap_syscall(); +// // println!("token address {:?}", token_address); + +// let token = Token { +// token_address: token_address, +// owner: recipient, +// creator: owner, +// name, +// symbol, +// total_supply: initial_supply, +// initial_supply: initial_supply, +// created_at: get_block_timestamp(), +// token_type: Option::None, +// is_unruggable: is_unruggable +// }; + +// self.token_created.entry(token_address).write(token); + +// let total_token = self.total_token.read(); +// if total_token == 0 { +// self.total_token.write(1); +// self.array_coins.entry(0).write(token); +// } else { +// self.total_token.write(total_token + 1); +// self.array_coins.entry(total_token).write(token); +// } + +// self +// .emit( +// CreateToken { +// caller: get_caller_address(), +// token_address: token_address, +// symbol: symbol, +// name: name, +// initial_supply, +// total_supply: initial_supply.clone(), +// is_unruggable: is_unruggable +// } +// ); +// token_address +// } + + +// fn _launch_token( +// ref self: ContractState, +// coin_address: ContractAddress, +// caller: ContractAddress, +// creator: ContractAddress, +// is_unruggable: bool +// ) { +// // let caller = get_caller_address(); +// let token = self.token_created.read(coin_address); + +// // TODO +// // Maybe not needed because you can also create the coin everyhwhere (Unrug) and launch +// let mut token_to_use = self.default_token.read(); +// let mut quote_token_address = token_to_use.token_address.clone(); +// let bond_type = BondingType::Linear; +// // let erc20 = IERC20Dispatcher { contract_address: quote_token_address }; +// let memecoin = IERC20Dispatcher { contract_address: coin_address }; +// let total_supply = memecoin.total_supply(); +// let threshold_liquidity = self.threshold_liquidity.read(); +// let protocol_fee_percent = self.protocol_fee_percent.read(); +// let creator_fee_percent = self.creator_fee_percent.read(); + +// // let threshold = pool.threshold_liquidity; + +// // TODO calculate initial key price based on +// // MC +// // Threshold liquidity +// // total supply + +// // Total supply / 5 to get 20% of supply add after threshold +// let liquidity_supply = total_supply / LIQUIDITY_RATIO; +// let supply_distribution = total_supply - liquidity_supply; +// let liquidity_available = total_supply - liquidity_supply; + +// // let (slope, init_price) = self._calculate_pricing(total_supply - liquidity_supply); +// let starting_price = calculate_pricing( +// threshold_liquidity.clone(), supply_distribution.clone() +// ); +// let slope = calculate_slope( +// threshold_liquidity.clone(), starting_price.clone(), supply_distribution.clone() +// ); +// // let starting_price = threshold_liquidity / total_supply; +// // // @TODO Deploy an ERC404 +// // // Option for liquidity providing and Trading +// let launch_token_pump = TokenLaunch { +// owner: caller, +// creator: caller, +// token_address: coin_address, // CREATE 404 +// total_supply: total_supply, +// // available_supply: total_supply, +// available_supply: supply_distribution, +// initial_available_supply: supply_distribution, +// initial_pool_supply: liquidity_supply, +// // available_supply:liquidity_supply, +// // Todo price by pricetype after fix Enum instantiate +// bonding_curve_type: Option::Some(bond_type), +// // bonding_curve_type: BondingType, +// created_at: get_block_timestamp(), +// token_quote: token_to_use.clone(), +// starting_price: starting_price.clone(), +// // starting_price: token_to_use.starting_price, +// price: starting_price.clone(), +// // price:init_price, +// liquidity_raised: 0_u256, +// total_token_holded: 0_u256, +// is_liquidity_launch: false, +// slope: slope, +// threshold_liquidity: threshold_liquidity, +// liquidity_type: Option::None, +// protocol_fee_percent: protocol_fee_percent, +// creator_fee_percent: creator_fee_percent +// }; +// // Send supply need to launch your coin +// let amount_needed = total_supply.clone(); +// // println!("amount_needed {:?}", amount_needed); +// let allowance = memecoin.allowance(caller, get_contract_address()); +// // println!("test allowance contract {:?}", allowance); +// let balance_contract = memecoin.balance_of(get_contract_address()); + +// let is_memecoin = is_unruggable; +// // let is_memecoin = factory.is_memecoin(memecoin.contract_address); +// // if balance_contract < total_supply && !is_memecoin { +// if balance_contract < total_supply { +// // && !is_memecoin +// assert(allowance >= amount_needed, 'no supply provided'); +// if allowance >= amount_needed { +// // println!("allowance > amount_needed{:?}", allowance > amount_needed); +// memecoin +// .transfer_from( +// caller, get_contract_address(), total_supply - balance_contract +// ); +// } +// } + +// // memecoin.transfer_from(get_caller_address(), get_contract_address(), amount_needed); +// self.launched_coins.entry(coin_address).write(launch_token_pump.clone()); + +// let total_launch = self.total_launch.read(); +// if total_launch == 0 { +// self.total_launch.write(1); +// self.array_launched_coins.entry(0).write(launch_token_pump); +// } else { +// self.total_launch.write(total_launch + 1); +// self.array_launched_coins.entry(total_launch).write(launch_token_pump); +// } +// self +// .emit( +// CreateLaunch { +// caller: get_caller_address(), +// token_address: coin_address, +// amount: 0, +// price: starting_price, +// total_supply: total_supply, +// slope: slope, +// threshold_liquidity: threshold_liquidity, +// quote_token_address: quote_token_address, +// is_unruggable: is_unruggable +// } +// ); +// } + +// // TODO add liquidity to Ekubo, Jediswap and others exchanges enabled +// // TODO Increased liquidity if pool already exist +// fn _add_liquidity( +// ref self: ContractState, coin_address: ContractAddress, exchange: SupportedExchanges +// ) { +// match exchange { +// SupportedExchanges::Jediswap => { self._add_liquidity_jediswap(coin_address) }, +// SupportedExchanges::Ekubo => { self._add_liquidity_ekubo(coin_address); }, +// } +// let mut launch_to_update = self.launched_coins.read(coin_address); +// launch_to_update.is_liquidity_launch = true; +// self.launched_coins.entry(coin_address).write(launch_to_update.clone()); +// } + + +// fn _supply_liquidity_ekubo( +// ref self: ContractState, +// pool_key: PoolKey, +// token: ContractAddress, +// amount: u256, +// bounds: Bounds +// ) -> u64 { +// // println!("mint deposit NOW HERE: {}", 1); + +// let positions_address = self.positions.read(); +// let positions = IPositionsDispatcher { contract_address: positions_address }; +// // println!("mint deposit NOW HERE: {}", 2); + +// // The token must be transferred to the positions contract before calling mint. +// IERC20Dispatcher { contract_address: token } +// .transfer(recipient: positions.contract_address, :amount); +// // println!("mint deposit NOW HERE: {}", 3); + +// let (id, liquidity) = positions.mint_and_deposit(pool_key, bounds, min_liquidity: 0); +// // let (id, liquidity, _, _) = positions +// // .mint_and_deposit_and_clear_both(pool_key, bounds, min_liquidity: 0); +// // println!("mint deposit NOW HERE: {}", 4); +// id +// } + +// fn _add_liquidity_ekubo( +// ref self: ContractState, coin_address: ContractAddress, +// // params: EkuboLaunchParameters +// ) -> (u64, EkuboLP) { +// // TODO params of Ekubo launch +// // Init price and params of liquidity + +// // TODO assert of threshold and MC reached +// let launch = self.launched_coins.read(coin_address); +// assert(launch.liquidity_raised >= launch.threshold_liquidity, 'no threshold raised'); +// assert(launch.is_liquidity_launch == false, 'liquidity already launch'); + +// // TODO calculate price + +// // let launch_price = launch.initial_pool_supply / launch.threshold_liquidity; +// // println!("launch_price {:?}", launch_price); + +// // let price_u128:u128=launch_price.try_into().unwrap(); +// // println!("price_u128 {:?}", price_u128); + +// // let starting_price = i129 { sign: true, mag: 100_u128 }; +// // let starting_price = i129 { sign: true, mag: 100_u128 }; +// // let starting_price = i129 { sign: true, mag: price_u128 }; +// let starting_price: i129 = calculate_starting_price_launch( +// launch.initial_pool_supply.clone(), launch.threshold_liquidity.clone() +// ); +// let lp_meme_supply = launch.initial_pool_supply; + +// // let lp_meme_supply = launch.initial_available_supply - launch.available_supply; + +// let params: EkuboLaunchParameters = EkuboLaunchParameters { +// owner: launch.owner, +// token_address: launch.token_address, +// quote_address: launch.token_quote.token_address, +// lp_supply: lp_meme_supply, +// // lp_supply: launch.liquidity_raised, +// pool_params: EkuboPoolParameters { +// fee: 0xc49ba5e353f7d00000000000000000, +// tick_spacing: 5000, +// starting_price, +// bound: calculate_aligned_bound_mag(starting_price, 2, 5000), +// } +// }; + +// // println!("Bound computed: {}", params.pool_params.bound); + +// // Register the token in Ekubo Registry +// // let registry_address = self.ekubo_registry.read(); +// // let registry = ITokenRegistryDispatcher { contract_address: registry_address }; + +// let ekubo_core_address = self.core.read(); +// let ekubo_exchange_address = self.ekubo_exchange_address.read(); +// let memecoin = EKIERC20Dispatcher { contract_address: params.token_address }; +// //TODO token decimal, amount of 1 token? + +// // println!("RIGHT HERE: {}", 1); + +// let pool = self.launched_coins.read(coin_address); +// let dex_address = self.core.read(); +// let positions_ekubo = self.positions.read(); +// memecoin.approve(ekubo_exchange_address, lp_meme_supply); +// memecoin.approve(ekubo_core_address, lp_meme_supply); +// memecoin.approve(positions_ekubo, lp_meme_supply); +// assert!(memecoin.contract_address == params.token_address, "Token address mismatch"); +// let base_token = EKIERC20Dispatcher { contract_address: params.quote_address }; +// //TODO token decimal, amount of 1 token? +// // let pool = self.launched_coins.read(coin_address); +// base_token.approve(ekubo_exchange_address, pool.liquidity_raised); +// base_token.approve(ekubo_core_address, pool.liquidity_raised); +// let core = ICoreDispatcher { contract_address: ekubo_core_address }; +// // Call the core with a callback to deposit and mint the LP tokens. + +// // println!("HERE launch callback: {}", 2); + +// let (id, position) = call_core_with_callback::< +// // let span = call_core_with_callbac00k::< +// CallbackData, (u64, EkuboLP) +// >(core, @CallbackData::LaunchCallback(LaunchCallback { params })); +// // let (id,position) = self._supply_liquidity_ekubo_and_mint(coin_address, params); +// //TODO emit event +// let id_cast: u256 = id.try_into().unwrap(); + +// // println!("RIGHT HERE: {}", 3); + +// let mut launch_to_update = self.launched_coins.read(coin_address); +// launch_to_update.is_liquidity_launch = true; +// self.launched_coins.entry(coin_address).write(launch_to_update.clone()); + +// // println!("RIGHT HERE: {}", 4); + +// self +// .emit( +// LiquidityCreated { +// id: id_cast, +// pool: coin_address, +// asset: coin_address, +// quote_token_address: base_token.contract_address, +// owner: launch.owner, +// exchange: SupportedExchanges::Ekubo, +// is_unruggable: false +// } +// ); + +// (id, position) +// } + +// /// TODO fix change +// fn _check_common_launch_parameters( +// ref self: ContractState, launch_parameters: LaunchParameters +// ) -> (u256, u8) { +// let LaunchParameters { memecoin_address, +// transfer_restriction_delay, +// max_percentage_buy_launch, +// quote_address, +// initial_holders, +// initial_holders_amounts } = +// launch_parameters; +// let memecoin = IMemecoinDispatcher { contract_address: memecoin_address }; +// let erc20 = IERC20Dispatcher { contract_address: memecoin_address }; + +// // TODO fix assert +// // assert(self.is_memecoin(memecoin_address), errors::NOT_UNRUGGABLE); +// // assert(!self.is_memecoin(quote_address), errors::QUOTE_TOKEN_IS_MEMECOIN); +// assert(!memecoin.is_launched(), errors::ALREADY_LAUNCHED); +// // assert(get_caller_address() == memecoin.owner(), errors::CALLER_NOT_OWNER); +// assert(initial_holders.len() == initial_holders_amounts.len(), errors::ARRAYS_LEN_DIF); +// assert(initial_holders.len() <= MAX_HOLDERS_LAUNCH.into(), errors::MAX_HOLDERS_REACHED); + +// let initial_supply = erc20.total_supply(); + +// // Check that the sum of the amounts of initial holders does not exceed the max +// // allocatable supply for a team. +// let max_team_allocation = initial_supply +// .percent_mul(MAX_SUPPLY_PERCENTAGE_TEAM_ALLOCATION.into()); +// let mut team_allocation: u256 = 0; +// let mut i: usize = 0; +// loop { +// if i == initial_holders.len() { +// break; +// } + +// let address = *initial_holders.at(i); +// let amount = *initial_holders_amounts.at(i); + +// team_allocation += amount; +// assert(team_allocation <= max_team_allocation, errors::MAX_TEAM_ALLOCATION_REACHED); +// i += 1; +// }; + +// (team_allocation, unique_count(initial_holders).try_into().unwrap()) +// } + +// fn _add_internal_liquidity_unrug( +// ref self: ContractState, +// coin_address: ContractAddress, +// launch_params: LaunchParameters, +// ekubo_pool_params: EkuboPoolParameters +// ) -> (u64, EkuboLP) { +// let launch = self.launched_coins.read(coin_address); +// // let starting_price = i129 { sign: true, mag: 100_u128 }; + +// // let starting_price: i129 = self._calculate_starting_price_launch( +// // launch.initial_pool_supply.clone(), launch.threshold_liquidity.clone() +// // ); +// let starting_price: i129 = calculate_starting_price_launch( +// launch.initial_pool_supply.clone(), launch.threshold_liquidity.clone() +// ); + +// let lp_meme_supply = launch.initial_available_supply - launch.available_supply; + +// let lp_meme_supply = launch.initial_pool_supply; +// let lp_supply = launch.initial_pool_supply; + +// let params: EkuboLaunchParameters = EkuboLaunchParameters { +// owner: launch.owner, +// token_address: launch.token_address, +// quote_address: launch.token_quote.token_address, +// lp_supply: lp_meme_supply, +// // lp_supply: launch.liquidity_raised, +// pool_params: EkuboPoolParameters { +// fee: 0xc49ba5e353f7d00000000000000000, +// tick_spacing: 5000, +// starting_price, +// bound: calculate_aligned_bound_mag(starting_price, 2, 5000), +// } +// }; +// // let params: EkuboLaunchParameters = EkuboLaunchParameters { +// // owner: launch.owner, +// // token_address: launch.token_address, +// // quote_address: launch.token_quote.token_address, +// // lp_supply: lp_meme_supply, +// // // lp_supply: launch.liquidity_raised, +// // pool_params: EkuboPoolParameters { +// // fee: 0xc49ba5e353f7d00000000000000000, +// // tick_spacing: 5982, +// // starting_price, +// // bound: 88719042, +// // } +// // }; + +// let (team_allocation, pre_holders) = self +// ._check_common_launch_parameters(launch_params); + +// assert(launch.liquidity_raised >= launch.threshold_liquidity, 'no threshold raised'); +// assert(launch.is_liquidity_launch == false, 'liquidity already launch'); + +// assert( +// ekubo_pool_params.fee <= 0x51eb851eb851ec00000000000000000, errors::FEE_TOO_HIGH +// ); +// assert(ekubo_pool_params.tick_spacing >= 5982, errors::TICK_SPACING_TOO_LOW); +// assert(ekubo_pool_params.tick_spacing <= 19802, errors::TICK_SPACING_TOO_HIGH); +// assert(ekubo_pool_params.bound >= 88712960, errors::BOUND_TOO_LOW); + +// let LaunchParameters { memecoin_address, +// transfer_restriction_delay, +// max_percentage_buy_launch, +// quote_address, +// initial_holders, +// initial_holders_amounts } = +// launch_params; + +// // let launchpad_address = self.exchange_address(SupportedExchanges::Ekubo); +// let launchpad_address = self.ekubo_exchange_address.read(); + +// // let launchpad_address = self.exchange_address(SupportedExchanges::Ekubo); +// assert(launchpad_address.is_non_zero(), errors::EXCHANGE_ADDRESS_ZERO); +// assert(ekubo_pool_params.starting_price.mag.is_non_zero(), errors::PRICE_ZERO); + +// let erc20 = IERC20Dispatcher { contract_address: coin_address }; +// let ekubo_core_address = self.core.read(); + +// let memecoin = IERC20Dispatcher { contract_address: coin_address }; +// memecoin.approve(ekubo_core_address, lp_supply); + +// let core = ICoreDispatcher { contract_address: ekubo_core_address }; + +// let (id, position) = call_core_with_callback::< +// CallbackData, (u64, EkuboLP) +// >(core, @CallbackData::LaunchCallback(LaunchCallback { params })); + +// distribute_team_alloc(erc20, initial_holders, initial_holders_amounts); + +// let memecoin = IMemecoinDispatcher { contract_address: coin_address }; + +// memecoin +// .set_launched( +// LiquidityType::EkuboNFT(id), +// LiquidityParameters::Ekubo( +// EkuboLiquidityParameters { +// quote_address, ekubo_pool_parameters: ekubo_pool_params +// } +// ), +// :transfer_restriction_delay, +// :max_percentage_buy_launch, +// :team_allocation, +// ); +// // self +// // .emit( +// // MemecoinLaunched { +// // memecoin_address, quote_token: quote_address, exchange_name: 'Ekubo' +// // } +// // ); +// (id, position) +// } + + +// fn _add_internal_liquidity_unrug_lp( +// ref self: ContractState, +// caller: ContractAddress, +// coin_address: ContractAddress, +// quote_address: ContractAddress, +// lp_supply: u256, +// launch_params: LaunchParameters, +// ekubo_pool_params: EkuboPoolParameters +// ) -> (u64, EkuboLP) { +// let starting_price = i129 { sign: true, mag: 10_u128 }; + +// let params: EkuboLaunchParameters = EkuboLaunchParameters { +// owner: caller, +// token_address: coin_address, +// quote_address: quote_address, +// lp_supply: lp_supply, +// // lp_supply: launch.liquidity_raised, +// pool_params: ekubo_pool_params +// }; +// let (team_allocation, pre_holders) = self +// ._check_common_launch_parameters(launch_params); + +// assert( +// ekubo_pool_params.fee <= 0x51eb851eb851ec00000000000000000, errors::FEE_TOO_HIGH +// ); +// assert(ekubo_pool_params.tick_spacing >= 5982, errors::TICK_SPACING_TOO_LOW); +// assert(ekubo_pool_params.tick_spacing <= 19802, errors::TICK_SPACING_TOO_HIGH); +// assert(ekubo_pool_params.bound >= 88712960, errors::BOUND_TOO_LOW); + +// let LaunchParameters { memecoin_address, +// transfer_restriction_delay, +// max_percentage_buy_launch, +// quote_address, +// initial_holders, +// initial_holders_amounts } = +// launch_params; + +// let launchpad_address = self.ekubo_exchange_address.read(); +// assert(launchpad_address.is_non_zero(), errors::EXCHANGE_ADDRESS_ZERO); +// assert(ekubo_pool_params.starting_price.mag.is_non_zero(), errors::PRICE_ZERO); + +// let erc20 = IERC20Dispatcher { contract_address: coin_address }; +// let ekubo_core_address = self.core.read(); + +// let memecoin = IERC20Dispatcher { contract_address: coin_address }; +// memecoin.approve(ekubo_core_address, lp_supply); + +// let core = ICoreDispatcher { contract_address: ekubo_core_address }; + +// let (id, position) = call_core_with_callback::< +// CallbackData, (u64, EkuboLP) +// >(core, @CallbackData::LaunchCallback(LaunchCallback { params })); + +// distribute_team_alloc(erc20, initial_holders, initial_holders_amounts); + +// let memecoin = IMemecoinDispatcher { contract_address: coin_address }; + +// memecoin +// .set_launched( +// LiquidityType::EkuboNFT(id), +// LiquidityParameters::Ekubo( +// EkuboLiquidityParameters { +// quote_address, ekubo_pool_parameters: ekubo_pool_params +// } +// ), +// :transfer_restriction_delay, +// :max_percentage_buy_launch, +// :team_allocation, +// ); +// // self +// // .emit( +// // MemecoinLaunched { +// // memecoin_address, quote_token: quote_address, exchange_name: 'Ekubo' +// // } +// // ); +// (id, position) +// } + +// // TODO add liquidity or increase +// // Better params of Mint +// fn _add_liquidity_jediswap(ref self: ContractState, coin_address: ContractAddress) { +// let mut factory_address = self.address_jediswap_factory_v2.read(); +// let nft_router_address = self.address_jediswap_nft_router_v2.read(); + +// if nft_router_address.is_zero() { +// return; +// } +// let nft_router = IJediswapNFTRouterV2Dispatcher { +// contract_address: nft_router_address +// }; + +// let facto_address = nft_router.factory(); + +// if !facto_address.is_zero() { +// factory_address = facto_address.clone(); +// } + +// if factory_address.is_zero() { +// return; +// } +// // let jediswap_address = self.exchange_configs.read(SupportedExchanges::Jediswap); +// // +// let fee: u32 = 10_000; +// let factory = IJediswapFactoryV2Dispatcher { contract_address: factory_address }; +// let launch = self.launched_coins.read(coin_address); +// let token_a = launch.token_address.clone(); +// let asset_token_address = launch.token_address.clone(); +// let quote_token_address = launch.token_quote.token_address.clone(); +// let token_b = launch.token_quote.token_address.clone(); +// // TODO tokens check +// // assert!(token_a != token_b, "same token"); +// // Look if pool already exist +// // Init and Create pool if not exist +// let mut pool: ContractAddress = factory.get_pool(token_a, token_b, fee); +// let sqrt_price_X96 = 0; // TODO change sqrt_price_X96 + +// // TODO check if pool exist +// // Pool need to be create +// // Better params for Liquidity launching +// // let token_asset = IERC20Dispatcher { contract_address: token_a }; + +// // TODO +// // Used total supply if coin is minted +// // let total_supply_now = token_asset.total_supply().clone(); +// let total_supply = launch.total_supply.clone(); +// let liquidity_raised = launch.liquidity_raised.clone(); +// // let total_supply = launch.total_supply.clone(); + +// let amount_coin_liq = total_supply / LIQUIDITY_RATIO; +// let amount0_desired = 0; +// let amount1_desired = 0; +// let amount0_min = amount_coin_liq; +// let amount1_min = liquidity_raised; +// let tick_lower: i32 = 0; +// let tick_upper: i32 = 0; +// let deadline: u64 = get_block_timestamp(); + +// // @TODO check mint params + +// if pool.into() == 0_felt252 { +// pool = factory.create_pool(token_a, token_b, fee); +// pool = nft_router.create_and_initialize_pool(token_a, token_b, fee, sqrt_price_X96); +// // TODO Increase liquidity with router if exist +// // Approve token asset and quote to be transferred +// let token_asset = IERC20Dispatcher { contract_address: token_a }; +// let token_quote = IERC20Dispatcher { contract_address: token_b }; +// token_asset.approve(nft_router_address, amount_coin_liq); +// token_quote.approve(nft_router_address, launch.liquidity_raised); +// // TODO verify Mint params +// // Test snforge in Sepolia +// let mint_params = MintParams { +// token0: token_a, +// token1: token_b, +// fee: fee, +// tick_lower: tick_lower, +// tick_upper: tick_upper, +// amount0_desired: amount0_desired, +// amount1_desired: amount1_desired, +// amount0_min: amount0_min, +// amount1_min: amount1_min, +// recipient: launch.owner, // TODO add +// deadline: deadline, +// }; + +// let (token_id, _, _, _) = nft_router.mint(mint_params); +// // TODO Locked LP token +// self +// .emit( +// LiquidityCreated { +// id: token_id, +// pool: pool, +// quote_token_address: quote_token_address, +// // token_id:token_id, +// owner: launch.owner, +// asset: asset_token_address, +// exchange: SupportedExchanges::Jediswap, +// is_unruggable: false +// } +// ); +// } else { // TODO +// // Increase liquidity of this pool. +// } +// } +// } +// } diff --git a/onchain/cairo/src/tests/launchpad_tests.cairo b/onchain/cairo/src/tests/launchpad_tests.cairo index 7ac22d85..ff8ed5fb 100644 --- a/onchain/cairo/src/tests/launchpad_tests.cairo +++ b/onchain/cairo/src/tests/launchpad_tests.cairo @@ -1,1946 +1,1946 @@ -#[cfg(test)] -mod launchpad_tests { - use afk::interfaces::factory::{IFactory, IFactoryDispatcher, IFactoryDispatcherTrait}; - use afk::launchpad::launchpad::LaunchpadMarketplace::{Event as LaunchpadEvent}; - use afk::launchpad::launchpad::{ - ILaunchpadMarketplaceDispatcher, ILaunchpadMarketplaceDispatcherTrait, - }; - use afk::tokens::erc20::{IERC20, IERC20Dispatcher, IERC20DispatcherTrait}; - use afk::tokens::memecoin::{IMemecoin, IMemecoinDispatcher, IMemecoinDispatcherTrait}; - use afk::types::launchpad_types::{ - CreateToken, TokenQuoteBuyCoin, BondingType, CreateLaunch, SetJediswapNFTRouterV2, - SetJediswapV2Factory, SupportedExchanges, EkuboLP, EkuboPoolParameters, TokenLaunch, - EkuboLaunchParameters, LaunchParameters - }; - - use core::num::traits::Zero; - use core::traits::Into; - use ekubo::interfaces::core::{ICore, ICoreDispatcher, ICoreDispatcherTrait}; - use ekubo::interfaces::positions::{IPositionsDispatcher, IPositionsDispatcherTrait}; - use ekubo::interfaces::token_registry::{ - ITokenRegistryDispatcher, ITokenRegistryDispatcherTrait, - }; - - use ekubo::types::i129::i129; - use ekubo::types::keys::PoolKey; - use openzeppelin::utils::serde::SerializedAppend; - use snforge_std::{ - declare, ContractClass, ContractClassTrait, spy_events, start_cheat_caller_address, - start_cheat_caller_address_global, stop_cheat_caller_address, - stop_cheat_caller_address_global, start_cheat_block_timestamp, DeclareResultTrait, - EventSpyAssertionsTrait - }; - use starknet::syscalls::call_contract_syscall; - - use starknet::{ContractAddress, ClassHash, class_hash::class_hash_const}; - - // fn DEFAULT_INITIAL_SUPPLY() -> u256 { - // // 21_000_000 * pow_256(10, 18) - // 100_000_000 - // // * pow_256(10, 18) - // } - fn DEFAULT_INITIAL_SUPPLY() -> u256 { - // 21_000_000 * pow_256(10, 18) - 100 - // * pow_256(10, 18) - } - - // const INITIAL_KEY_PRICE:u256=1/100; - const INITIAL_SUPPLY_DEFAULT: u256 = 100_000_000; - const INITIAL_KEY_PRICE: u256 = 1; - const STEP_LINEAR_INCREASE: u256 = 1; - const THRESHOLD_LIQUIDITY: u256 = 10; - const THRESHOLD_MARKET_CAP: u256 = 500; - const MIN_FEE_PROTOCOL: u256 = 10; //0.1% - const MAX_FEE_PROTOCOL: u256 = 1000; //10% - const MID_FEE_PROTOCOL: u256 = 100; //1% - const MIN_FEE_CREATOR: u256 = 100; //1% - const MID_FEE_CREATOR: u256 = 1000; //10% - const MAX_FEE_CREATOR: u256 = 5000; //50% - // const INITIAL_KEY_PRICE: u256 = 1 / 10_000; - // const THRESHOLD_LIQUIDITY: u256 = 10; - // const THRESHOLD_LIQUIDITY: u256 = 10_000; - - const RATIO_SUPPLY_LAUNCH: u256 = 5; - const LIQUIDITY_SUPPLY: u256 = INITIAL_SUPPLY_DEFAULT / RATIO_SUPPLY_LAUNCH; - const BUYABLE: u256 = INITIAL_SUPPLY_DEFAULT / RATIO_SUPPLY_LAUNCH; - - const LIQUIDITY_RATIO: u256 = 5; - - fn FACTORY_ADDRESS() -> ContractAddress { - 0x01a46467a9246f45c8c340f1f155266a26a71c07bd55d36e8d1c7d0d438a2dbc.try_into().unwrap() - } - - fn EKUBO_EXCHANGE_ADDRESS() -> ContractAddress { - 0x00000005dd3d2f4429af886cd1a3b08289dbcea99a294197e9eb43b0e0325b4b.try_into().unwrap() - } - - // fn EKUBO_EXCHANGE_ADDRESS() -> ContractAddress { - // 0x02bd1cdd5f7f17726ae221845afd9580278eebc732bc136fe59d5d94365effd5.try_into().unwrap() - // } - - fn EKUBO_CORE() -> ContractAddress { - 0x00000005dd3d2f4429af886cd1a3b08289dbcea99a294197e9eb43b0e0325b4b.try_into().unwrap() - } - - fn EKUBO_POSITIONS() -> ContractAddress { - 0x02e0af29598b407c8716b17f6d2795eca1b471413fa03fb145a5e33722184067.try_into().unwrap() - } - - fn EKUBO_REGISTRY() -> ContractAddress { - 0x0013e25867b6eef62703735aa4cfa7754e72f4e94a56c9d3d9ad8ebe86cee4aa.try_into().unwrap() - } - - fn JEDISWAP_FACTORY() -> ContractAddress { - 0x01aa950c9b974294787de8df8880ecf668840a6ab8fa8290bf2952212b375148.try_into().unwrap() - } - - fn JEDISWAP_NFT_V2() -> ContractAddress { - 0x0469b656239972a2501f2f1cd71bf4e844d64b7cae6773aa84c702327c476e5b.try_into().unwrap() - } - - - fn SALT() -> felt252 { - 'salty'.try_into().unwrap() - } - - // Constants - fn OWNER() -> ContractAddress { - // 'owner'.try_into().unwrap() - 123.try_into().unwrap() - } - - fn RECIPIENT() -> ContractAddress { - 'recipient'.try_into().unwrap() - } - - fn SPENDER() -> ContractAddress { - 'spender'.try_into().unwrap() - } - - fn ALICE() -> ContractAddress { - 'alice'.try_into().unwrap() - } - - fn BOB() -> ContractAddress { - 'bob'.try_into().unwrap() - } - - fn NAME() -> felt252 { - 'name'.try_into().unwrap() - } - - fn SYMBOL() -> felt252 { - 'symbol'.try_into().unwrap() - } - - // Math - fn pow_256(self: u256, mut exponent: u8) -> u256 { - if self.is_zero() { - return 0; - } - let mut result = 1; - let mut base = self; - - loop { - if exponent & 1 == 1 { - result = result * base; - } - - exponent = exponent / 2; - if exponent == 0 { - break result; - } - - base = base * base; - } - } - - // Declare and create all contracts - // Return sender_address, Erc20 quote and Launchpad contract - fn request_fixture() -> (ContractAddress, IERC20Dispatcher, ILaunchpadMarketplaceDispatcher) { - // println!("request_fixture"); - let erc20_class = declare_erc20(); - let meme_class = declare_memecoin(); - let launch_class = declare_launchpad(); - request_fixture_custom_classes(*erc20_class, *meme_class, *launch_class) - } - - fn request_fixture_custom_classes( - erc20_class: ContractClass, meme_class: ContractClass, launch_class: ContractClass - ) -> (ContractAddress, IERC20Dispatcher, ILaunchpadMarketplaceDispatcher) { - let sender_address: ContractAddress = 123.try_into().unwrap(); - let erc20 = deploy_erc20(erc20_class, 'USDC token', 'USDC', 1_000_000, sender_address); - let token_address = erc20.contract_address.clone(); - let launchpad = deploy_launchpad( - launch_class, - sender_address, - token_address.clone(), - INITIAL_KEY_PRICE, - STEP_LINEAR_INCREASE, - meme_class.class_hash, - THRESHOLD_LIQUIDITY, - THRESHOLD_MARKET_CAP, - FACTORY_ADDRESS(), - EKUBO_REGISTRY(), - EKUBO_CORE(), - EKUBO_POSITIONS(), - EKUBO_EXCHANGE_ADDRESS() - // ITokenRegistryDispatcher { contract_address: EKUBO_REGISTRY() }, - // ICoreDispatcher { contract_address: EKUBO_CORE() }, - // IPositionsDispatcher { contract_address: EKUBO_POSITIONS() }, - ); - // let launchpad = deploy_launchpad( - // launch_class, - // sender_address, - // token_address.clone(), - // INITIAL_KEY_PRICE * pow_256(10,18), - // // INITIAL_KEY_PRICE, - // // STEP_LINEAR_INCREASE, - // STEP_LINEAR_INCREASE * pow_256(10,18), - // erc20_class.class_hash, - // THRESHOLD_LIQUIDITY * pow_256(10,18), - // // THRESHOLD_LIQUIDITY, - // THRESHOLD_MARKET_CAP * pow_256(10,18), - // // THRESHOLD_MARKET_CAP - // ); - - start_cheat_caller_address(launchpad.contract_address, OWNER()); - launchpad.set_address_jediswap_factory_v2(JEDISWAP_FACTORY()); - launchpad.set_address_jediswap_nft_router_v2(JEDISWAP_NFT_V2()); - (sender_address, erc20, launchpad) - } - - fn deploy_launchpad( - class: ContractClass, - admin: ContractAddress, - token_address: ContractAddress, - initial_key_price: u256, - step_increase_linear: u256, - coin_class_hash: ClassHash, - threshold_liquidity: u256, - threshold_marketcap: u256, - factory_address: ContractAddress, - ekubo_registry: ContractAddress, - core: ContractAddress, - positions: ContractAddress, - ekubo_exchange_address: ContractAddress, - // ekubo_registry: ITokenRegistryDispatcher, - // core: ICoreDispatcher, - // positions: IPositionsDispatcher, - ) -> ILaunchpadMarketplaceDispatcher { - // println!("deploy marketplace"); - let mut calldata = array![admin.into()]; - calldata.append_serde(initial_key_price); - calldata.append_serde(token_address); - calldata.append_serde(step_increase_linear); - calldata.append_serde(coin_class_hash); - calldata.append_serde(threshold_liquidity); - calldata.append_serde(threshold_marketcap); - calldata.append_serde(factory_address); - calldata.append_serde(ekubo_registry); - calldata.append_serde(core); - calldata.append_serde(positions); - calldata.append_serde(ekubo_exchange_address); - let (contract_address, _) = class.deploy(@calldata).unwrap(); - ILaunchpadMarketplaceDispatcher { contract_address } - } - - fn declare_launchpad() -> @ContractClass { - declare("LaunchpadMarketplace").unwrap().contract_class() - } - - fn declare_erc20() -> @ContractClass { - declare("ERC20").unwrap().contract_class() - } - - fn declare_memecoin() -> @ContractClass { - declare("Memecoin").unwrap().contract_class() - } - - - fn deploy_erc20( - class: ContractClass, - name: felt252, - symbol: felt252, - initial_supply: u256, - recipient: ContractAddress - ) -> IERC20Dispatcher { - let mut calldata = array![]; - - name.serialize(ref calldata); - symbol.serialize(ref calldata); - (2 * initial_supply).serialize(ref calldata); - recipient.serialize(ref calldata); - 18_u8.serialize(ref calldata); - - let (contract_address, _) = class.deploy(@calldata).unwrap(); - - IERC20Dispatcher { contract_address } - } - - - fn run_buy_by_amount( - launchpad: ILaunchpadMarketplaceDispatcher, - erc20: IERC20Dispatcher, - memecoin: IERC20Dispatcher, - amount_quote: u256, - token_address: ContractAddress, - sender_address: ContractAddress, - ) { - start_cheat_caller_address(erc20.contract_address, sender_address); - erc20.approve(launchpad.contract_address, amount_quote); - let allowance = erc20.allowance(sender_address, launchpad.contract_address); - // println!("test allowance erc20 {}", allowance); - stop_cheat_caller_address(erc20.contract_address); - - start_cheat_caller_address(launchpad.contract_address, sender_address); - println!("buy coin {:?}", amount_quote,); - // launchpad.buy_coin_by_quote_amount(token_address, amount_quote, Option::None); - launchpad.buy_coin_by_quote_amount(token_address, amount_quote); - stop_cheat_caller_address(launchpad.contract_address); - } - - - fn run_sell_by_amount( - launchpad: ILaunchpadMarketplaceDispatcher, - erc20: IERC20Dispatcher, - memecoin: IERC20Dispatcher, - amount_quote: u256, - token_address: ContractAddress, - sender_address: ContractAddress, - ) { - println!("sell coin for amount quote{:?}", amount_quote); - let allowance = memecoin.allowance(sender_address, launchpad.contract_address); - println!("test allowance meme coin{}", allowance); - launchpad.sell_coin(token_address, amount_quote); - } - - fn run_calculation( - launchpad: ILaunchpadMarketplaceDispatcher, - amount_quote: u256, - token_address: ContractAddress, - sender_address: ContractAddress, - is_decreased: bool, - is_quote_amount: bool - ) -> u256 { - start_cheat_caller_address(launchpad.contract_address, sender_address); - println!("calcul amount"); - let amount = launchpad - .get_coin_amount_by_quote_amount(token_address, amount_quote, is_decreased); - println!("amount to receive {:?}", amount); - amount - } - - fn calculate_slope(total_supply: u256) -> u256 { - let liquidity_supply = total_supply / LIQUIDITY_RATIO; - let liquidity_available = total_supply - liquidity_supply; - let slope = (2 * THRESHOLD_LIQUIDITY) / (liquidity_available * (liquidity_available - 1)); - slope - } - - #[test] - #[fork("Mainnet")] - fn launchpad_buy_all() { - println!("launchpad_buy_all"); - let (sender_address, erc20, launchpad) = request_fixture(); - start_cheat_caller_address_global(sender_address); - start_cheat_caller_address(erc20.contract_address, sender_address); - let mut spy = spy_events(); - - // Call a view function of the contract - // Check default token used - let default_token = launchpad.get_default_token(); - assert(default_token.token_address == erc20.contract_address, 'no default token'); - assert(default_token.starting_price == INITIAL_KEY_PRICE, 'no init price'); - start_cheat_caller_address(launchpad.contract_address, sender_address); - println!("create and launch token"); - let token_address = launchpad - .create_and_launch_token( - // owner: OWNER(), - symbol: SYMBOL(), - name: NAME(), - initial_supply: DEFAULT_INITIAL_SUPPLY(), - contract_address_salt: SALT(), - is_unruggable: false - ); - println!("test token_address {:?}", token_address); - let memecoin = IERC20Dispatcher { contract_address: token_address }; - - // All buy - // run_buy_by_amount( - // launchpad, erc20, memecoin, THRESHOLD_LIQUIDITY, token_address, sender_address, - // ); - println!("first buy {:?}", token_address); - - run_buy_by_amount( - launchpad, erc20, memecoin, THRESHOLD_LIQUIDITY - 1, token_address, sender_address, - ); - - run_buy_by_amount(launchpad, erc20, memecoin, 1, token_address, sender_address,); - - // let expected_launch_token_event = LaunchpadEvent::CreateLaunch( - // CreateLaunch { - // caller: OWNER(), - // token_address: token_address, - // amount: 0, - // price: INITIAL_KEY_PRICE, - // total_supply: DEFAULT_INITIAL_SUPPLY(), - // slope: slope, - // threshold_liquidity: THRESHOLD_LIQUIDITY, - // quote_token_address: erc20.contract_address, - // } - // ); - // spy.assert_emitted(@array![(launchpad.contract_address, expected_launch_token_event)]); - let launched_token = launchpad.get_coin_launch(token_address); - let default_supply = DEFAULT_INITIAL_SUPPLY(); - // assert(launched_token.owner == OWNER(), 'wrong owner'); - assert(launched_token.token_address == token_address, 'wrong token address'); - assert(launched_token.total_supply == DEFAULT_INITIAL_SUPPLY(), 'wrong initial supply'); - assert( - launched_token.bonding_curve_type.unwrap() == BondingType::Linear, 'wrong type curve' - ); - assert(launched_token.liquidity_raised == THRESHOLD_LIQUIDITY, 'wrong liq raised'); - assert(launched_token.initial_pool_supply == default_supply / 5_u256, 'wrong init pool'); - // assert( - // launched_token.total_token_holded >= default_supply - // - launched_token.initial_pool_supply, - // 'wrong token holded' - // ); - assert( - launched_token.token_quote.token_address == erc20.contract_address, 'wrong token quote' - ); - } - - #[test] - #[fork("Mainnet")] - fn launchpad_end_to_end() { - println!("launchpad_end_to_end"); - let (sender_address, erc20, launchpad) = request_fixture(); - start_cheat_caller_address_global(sender_address); - start_cheat_caller_address(erc20.contract_address, sender_address); - let mut spy = spy_events(); - - // Call a view function of the contract - // Check default token used - let default_token = launchpad.get_default_token(); - assert(default_token.token_address == erc20.contract_address, 'no default token'); - assert(default_token.starting_price == INITIAL_KEY_PRICE, 'no init price'); - start_cheat_caller_address(launchpad.contract_address, sender_address); - println!("create and launch token"); - let token_address = launchpad - .create_and_launch_token( - // owner: OWNER(), - symbol: SYMBOL(), - name: NAME(), - initial_supply: DEFAULT_INITIAL_SUPPLY(), - contract_address_salt: SALT(), - is_unruggable: false - ); - println!("test token_address {:?}", token_address); - let memecoin = IERC20Dispatcher { contract_address: token_address }; - - run_buy_by_amount(launchpad, erc20, memecoin, 1, token_address, sender_address,); - - run_sell_by_amount(launchpad, erc20, memecoin, 1, token_address, sender_address,); - // All buy - - run_buy_by_amount( - launchpad, erc20, memecoin, THRESHOLD_LIQUIDITY, token_address, sender_address, - ); - // let expected_launch_token_event = LaunchpadEvent::CreateLaunch( - // CreateLaunch { - // caller: OWNER(), - // token_address: token_address, - // amount: 0, - // price: initial_key_price, - // total_supply: DEFAULT_INITIAL_SUPPLY(), - // slope: slope, - // threshold_liquidity: THRESHOLD_LIQUIDITY, - // quote_token_address: erc20.contract_address, - // } - // ); - // spy.assert_emitted(@array![(launchpad.contract_address, expected_launch_token_event)]); - let launched_token = launchpad.get_coin_launch(token_address); - let default_supply = DEFAULT_INITIAL_SUPPLY(); - // assert(launched_token.owner == OWNER(), 'wrong owner'); - assert(launched_token.token_address == token_address, 'wrong token address'); - assert(launched_token.total_supply == DEFAULT_INITIAL_SUPPLY(), 'wrong initial supply'); - assert( - launched_token.bonding_curve_type.unwrap() == BondingType::Linear, 'wrong type curve' - ); - assert(launched_token.liquidity_raised == THRESHOLD_LIQUIDITY, 'wrong liq raised'); - assert(launched_token.initial_pool_supply == default_supply / 5_u256, 'wrong init pool'); - assert( - launched_token.total_token_holded >= default_supply - - launched_token.initial_pool_supply, - 'wrong token holded' - ); - assert( - launched_token.token_quote.token_address == erc20.contract_address, - 'wrong token - quote' - ); - } - - #[test] - #[fork("Mainnet")] - fn launchpad_integration() { - println!("launchpad_integration"); - - let (sender_address, erc20, launchpad) = request_fixture(); - start_cheat_caller_address_global(sender_address); - start_cheat_caller_address(erc20.contract_address, sender_address); - let default_token = launchpad.get_default_token(); - assert(default_token.token_address == erc20.contract_address, 'no default token'); - assert(default_token.starting_price == INITIAL_KEY_PRICE, 'no init price'); - start_cheat_caller_address(launchpad.contract_address, sender_address); - - let token_address = launchpad - .create_token( - recipient: OWNER(), - // owner: OWNER(), - symbol: SYMBOL(), - name: NAME(), - initial_supply: DEFAULT_INITIAL_SUPPLY(), - contract_address_salt: SALT(), - is_unruggable: false, - ); - // println!("test token_address {:?}", token_address); - let memecoin = IERC20Dispatcher { contract_address: token_address }; - start_cheat_caller_address(memecoin.contract_address, OWNER()); - - let balance_contract = memecoin.balance_of(launchpad.contract_address); - println!("test balance_contract {:?}", balance_contract); - - let total_supply = memecoin.total_supply(); - // println!(" memecoin total_supply {:?}", total_supply); - memecoin.approve(launchpad.contract_address, total_supply); - - // let allowance = memecoin.allowance(sender_address, launchpad.contract_address); - // println!("test allowance meme coin{}", allowance); - // memecoin.transfer(launchpad.contract_address, total_supply); - stop_cheat_caller_address(memecoin.contract_address); - - start_cheat_caller_address(launchpad.contract_address, sender_address); - - launchpad.launch_token(token_address); - let amount_first_buy = 1_u256; - - run_buy_by_amount( - launchpad, erc20, memecoin, amount_first_buy, token_address, sender_address, - ); - - // let mut total_amount_buy = amount_first_buy; - let mut amount_second = 1_u256; - run_buy_by_amount( - launchpad, erc20, memecoin, amount_second, token_address, sender_address, - ); - - // let mut total_amount_buy = amount_first_buy; - let mut last_amount = 8_u256; - run_buy_by_amount(launchpad, erc20, memecoin, last_amount, token_address, sender_address,); - } - - - #[test] - fn test_create_token() { - let (_, _, launchpad) = request_fixture(); - let mut spy = spy_events(); - - start_cheat_caller_address(launchpad.contract_address, OWNER()); - - let token_address = launchpad - .create_token( - recipient: OWNER(), - symbol: SYMBOL(), - name: NAME(), - initial_supply: DEFAULT_INITIAL_SUPPLY(), - contract_address_salt: SALT(), - is_unruggable: false, - ); - - let expected_event = LaunchpadEvent::CreateToken( - CreateToken { - caller: OWNER(), - token_address: token_address, - symbol: SYMBOL(), - name: NAME(), - initial_supply: DEFAULT_INITIAL_SUPPLY(), - total_supply: DEFAULT_INITIAL_SUPPLY(), - is_unruggable: false - } - ); - spy.assert_emitted(@array![(launchpad.contract_address, expected_event)]); - } - - // #[test] - // #[fork("Mainnet")] - // fn test_create_and_launch_token() { - // let (_, erc20, launchpad) = request_fixture(); - // let mut spy = spy_events(); - // let initial_key_price = THRESHOLD_LIQUIDITY / DEFAULT_INITIAL_SUPPLY(); - // let slope = calculate_slope(DEFAULT_INITIAL_SUPPLY()); - - // start_cheat_caller_address(launchpad.contract_address, OWNER()); - - // let token_address = launchpad - // .create_and_launch_token( - // symbol: SYMBOL(), - // name: NAME(), - // initial_supply: DEFAULT_INITIAL_SUPPLY(), - // contract_address_salt: SALT(), - // ); - - // let create_token_event = LaunchpadEvent::CreateToken( - // CreateToken { - // caller: OWNER(), - // token_address: token_address, - // symbol: SYMBOL(), - // name: NAME(), - // initial_supply: DEFAULT_INITIAL_SUPPLY(), - // total_supply: DEFAULT_INITIAL_SUPPLY(), - // } - // ); - - // let launch_token_event = LaunchpadEvent::CreateLaunch( - // CreateLaunch { - // caller: OWNER(), - // token_address: token_address, - // amount: 0, - // price: initial_key_price, - // total_supply: DEFAULT_INITIAL_SUPPLY(), - // slope: slope, - // threshold_liquidity: THRESHOLD_LIQUIDITY, - // quote_token_address: erc20.contract_address, - // is_unruggable:false - // } - // ); - - // spy - // .assert_emitted( - // @array![ - // (launchpad.contract_address, create_token_event), - // (launchpad.contract_address, launch_token_event) - // ] - // ); - // } - - #[test] - // #[fork("Mainnet")] - #[should_panic(expected: ('not launch',))] - fn test_launch_token_with_uncreated_token() { - let (_, erc20, launchpad) = request_fixture(); - - launchpad.launch_token(coin_address: erc20.contract_address); - } - - #[test] - // #[fork("Mainnet")] - #[should_panic(expected: ('no supply provided',))] - fn test_launch_token_with_no_supply_provided() { - let (_, _, launchpad) = request_fixture(); - - start_cheat_caller_address(launchpad.contract_address, OWNER()); - - let token_address = launchpad - .create_token( - recipient: OWNER(), - symbol: SYMBOL(), - name: NAME(), - initial_supply: DEFAULT_INITIAL_SUPPLY(), - contract_address_salt: SALT(), - is_unruggable: false, - ); - - launchpad.launch_token(coin_address: token_address); - } - - #[test] - // #[fork("Mainnet")] - fn test_launch_token() { - let (_, erc20, launchpad) = request_fixture(); - let mut spy = spy_events(); - let starting_price = THRESHOLD_LIQUIDITY / DEFAULT_INITIAL_SUPPLY(); - let slope = calculate_slope(DEFAULT_INITIAL_SUPPLY()); - - start_cheat_caller_address(launchpad.contract_address, OWNER()); - - let token_address = launchpad - .create_token( - recipient: launchpad.contract_address, - symbol: SYMBOL(), - name: NAME(), - initial_supply: DEFAULT_INITIAL_SUPPLY(), - contract_address_salt: SALT(), - is_unruggable: false, - ); - - launchpad.launch_token(coin_address: token_address); - - let expected_launch_token_event = LaunchpadEvent::CreateLaunch( - CreateLaunch { - caller: OWNER(), - token_address: token_address, - amount: 0, - price: starting_price, - total_supply: DEFAULT_INITIAL_SUPPLY(), - slope: slope, - threshold_liquidity: THRESHOLD_LIQUIDITY, - quote_token_address: erc20.contract_address, - is_unruggable: false, - } - ); - - spy.assert_emitted(@array![(launchpad.contract_address, expected_launch_token_event)]); - } - - - #[test] - // #[fork("Mainnet")] - #[should_panic(expected: ('no threshold raised',))] - fn test_launch_liquidity_when_no_threshold_raised() { - let (_, _, launchpad) = request_fixture(); - - start_cheat_caller_address(launchpad.contract_address, OWNER()); - - let token_address = launchpad - .create_and_launch_token( - symbol: SYMBOL(), - name: NAME(), - initial_supply: DEFAULT_INITIAL_SUPPLY(), - contract_address_salt: SALT(), - is_unruggable: false - ); - - launchpad.launch_liquidity(token_address); - } - - - #[test] - fn test_get_threshold_liquidity() { - let (_, _, launchpad) = request_fixture(); - assert( - THRESHOLD_LIQUIDITY == launchpad.get_threshold_liquidity(), 'wrong threshold liquidity' - ); - } - - #[test] - fn test_get_default_token() { - let (_, erc20, launchpad) = request_fixture(); - - let expected_token = TokenQuoteBuyCoin { - token_address: erc20.contract_address, - starting_price: INITIAL_KEY_PRICE, - price: INITIAL_KEY_PRICE, - is_enable: true, - step_increase_linear: STEP_LINEAR_INCREASE, - }; - - assert(expected_token == launchpad.get_default_token(), 'wrong default token'); - } - - #[test] - // #[fork("Mainnet")] - fn test_get_coin_launch() { - let (_, erc20, launchpad) = request_fixture(); - - start_cheat_caller_address(launchpad.contract_address, OWNER()); - - let token_address = launchpad - .create_and_launch_token( - symbol: SYMBOL(), - name: NAME(), - initial_supply: DEFAULT_INITIAL_SUPPLY(), - contract_address_salt: SALT(), - is_unruggable: false - ); - - let launched_token = launchpad.get_coin_launch(token_address); - - assert(launched_token.owner == OWNER(), 'wrong owner'); - assert(launched_token.token_address == token_address, 'wrong token address'); - assert(launched_token.total_supply == DEFAULT_INITIAL_SUPPLY(), 'wrong initial supply'); - assert( - launched_token.bonding_curve_type.unwrap() == BondingType::Linear, - 'wrong initial supply' - ); - assert(launched_token.price == 0_u256, 'wrong price'); - assert(launched_token.liquidity_raised == 0_u256, 'wrong liquidation raised'); - assert(launched_token.total_token_holded == 0_u256, 'wrong token holded'); - assert( - launched_token.token_quote.token_address == erc20.contract_address, 'wrong token quote' - ); - } - - #[test] - // #[fork("Mainnet")] - fn test_get_share_key_of_user() { - let (sender_address, erc20, launchpad) = request_fixture(); - - let token_address = launchpad - .create_and_launch_token( - symbol: SYMBOL(), - name: NAME(), - initial_supply: DEFAULT_INITIAL_SUPPLY(), - contract_address_salt: SALT(), - is_unruggable: false - ); - let memecoin = IERC20Dispatcher { contract_address: token_address }; - - let mut first_buy = 10_u256; - run_buy_by_amount(launchpad, erc20, memecoin, first_buy, token_address, sender_address,); - - let share_key = launchpad.get_share_key_of_user(sender_address, memecoin.contract_address); - - assert(share_key.owner == sender_address, 'wrong owner'); - assert(share_key.token_address == memecoin.contract_address, 'wrong token address'); - } - - #[test] - // #[fork("Mainnet")] - fn test_get_all_launch_tokens_and_coins() { - let (sender_address, erc20, launchpad) = request_fixture(); - let first_token: felt252 = 'token_1'; - let second_token: felt252 = 'token_2'; - let third_token: felt252 = 'token_3'; - - let first_token_addr = launchpad - .create_and_launch_token( - symbol: 'FRST', - name: first_token, - initial_supply: DEFAULT_INITIAL_SUPPLY(), - contract_address_salt: SALT(), - is_unruggable: false - ); - - let second_token_addr = launchpad - .create_and_launch_token( - symbol: 'SCND', - name: second_token, - initial_supply: DEFAULT_INITIAL_SUPPLY(), - contract_address_salt: SALT(), - is_unruggable: false - ); - - let third_token_addr = launchpad - .create_and_launch_token( - symbol: 'THRD', - name: third_token, - initial_supply: DEFAULT_INITIAL_SUPPLY(), - contract_address_salt: SALT(), - is_unruggable: false - ); - - let all_launched_coins = launchpad.get_all_coins(); - let all_launched_tokens = launchpad.get_all_launch(); - - assert(all_launched_coins.len() == 3, 'wrong number of coins'); - assert(all_launched_tokens.len() == 3, 'wrong number of tokens'); - assert(*all_launched_coins.at(0).name == first_token, 'wrong coin name'); - assert(*all_launched_coins.at(1).name == second_token, 'wrong coin name'); - assert(*all_launched_coins.at(2).name == third_token, 'wrong coin name'); - assert(*all_launched_tokens.at(0).token_address == first_token_addr, 'wrong token address'); - assert( - *all_launched_tokens.at(1).token_address == second_token_addr, 'wrong token address' - ); - assert(*all_launched_tokens.at(2).token_address == third_token_addr, 'wrong token address'); - } - - - #[test] - #[should_panic(expected: ('share too low',))] - fn test_sell_coin_when_share_too_low() { - let (sender_address, erc20, launchpad) = request_fixture(); - - start_cheat_caller_address(launchpad.contract_address, OWNER()); - - let token_address = launchpad - .create_and_launch_token( - symbol: SYMBOL(), - name: NAME(), - initial_supply: DEFAULT_INITIAL_SUPPLY(), - contract_address_salt: SALT(), - is_unruggable: false - ); - - let memecoin = IERC20Dispatcher { contract_address: token_address }; - - run_sell_by_amount( - launchpad, erc20, memecoin, THRESHOLD_LIQUIDITY, token_address, sender_address, - ); - } - - #[test] - #[should_panic(expected: ('liquidity <= amount',))] - fn test_sell_coin_when_quote_amount_is_greater_than_liquidity_raised() { - let (sender_address, erc20, launchpad) = request_fixture(); - - start_cheat_caller_address(launchpad.contract_address, sender_address); - - let token_address = launchpad - .create_and_launch_token( - symbol: SYMBOL(), - name: NAME(), - initial_supply: DEFAULT_INITIAL_SUPPLY(), - contract_address_salt: SALT(), - is_unruggable: false - ); - - let memecoin = IERC20Dispatcher { contract_address: token_address }; - - run_buy_by_amount(launchpad, erc20, memecoin, 10_u256, token_address, sender_address,); - - run_sell_by_amount(launchpad, erc20, memecoin, 20_u256, token_address, sender_address,); - } - - #[test] - #[fork("Mainnet")] - fn test_launchpad_end_to_end() { - let (sender_address, erc20, launchpad) = request_fixture(); - let starting_price = THRESHOLD_LIQUIDITY / DEFAULT_INITIAL_SUPPLY(); - let slope = calculate_slope(DEFAULT_INITIAL_SUPPLY()); - let mut spy = spy_events(); - // let mut spy = spy_events(SpyOn::One(launchpad.contract_address)); - - // start_cheat_caller_address_global(sender_address); - start_cheat_caller_address(erc20.contract_address, sender_address); - - let default_token = launchpad.get_default_token(); - - assert(default_token.token_address == erc20.contract_address, 'no default token'); - assert(default_token.starting_price == INITIAL_KEY_PRICE, 'no init price'); - assert( - default_token.step_increase_linear == STEP_LINEAR_INCREASE, 'no step_increase_linear' - ); - assert(default_token.is_enable == true, 'not enabled'); - - start_cheat_caller_address(launchpad.contract_address, sender_address); - - let token_address = launchpad - .create_and_launch_token( - symbol: SYMBOL(), - name: NAME(), - initial_supply: DEFAULT_INITIAL_SUPPLY(), - contract_address_salt: SALT(), - is_unruggable: false - ); - - let memecoin = IERC20Dispatcher { contract_address: token_address }; - let amount_first_buy = 10_u256; - - run_buy_by_amount( - launchpad, erc20, memecoin, amount_first_buy, token_address, sender_address, - ); - - run_sell_by_amount( - launchpad, erc20, memecoin, amount_first_buy, token_address, sender_address, - ); - - run_buy_by_amount( - launchpad, erc20, memecoin, THRESHOLD_LIQUIDITY, token_address, sender_address, - ); - - run_sell_by_amount( - launchpad, erc20, memecoin, THRESHOLD_LIQUIDITY, token_address, sender_address, - ); - - let expected_create_token_event = LaunchpadEvent::CreateToken( - CreateToken { - caller: sender_address, - token_address: token_address, - symbol: SYMBOL(), - name: NAME(), - initial_supply: DEFAULT_INITIAL_SUPPLY(), - total_supply: DEFAULT_INITIAL_SUPPLY(), - is_unruggable: false, - } - ); - - let expected_launch_token_event = LaunchpadEvent::CreateLaunch( - CreateLaunch { - caller: OWNER(), - token_address: token_address, - amount: 0, - price: starting_price, - total_supply: DEFAULT_INITIAL_SUPPLY(), - slope: slope, - threshold_liquidity: THRESHOLD_LIQUIDITY, - quote_token_address: erc20.contract_address, - is_unruggable: true - } - ); - - spy - .assert_emitted( - @array![ - (launchpad.contract_address, expected_create_token_event), - (launchpad.contract_address, expected_launch_token_event) - ] - ); - } - - - #[test] - #[fork("Mainnet")] - fn test_add_liquidity_ekubo() { - let (sender, erc20, launchpad) = request_fixture(); - start_cheat_caller_address(launchpad.contract_address, OWNER()); - let token_address = launchpad - .create_and_launch_token( - symbol: SYMBOL(), - name: NAME(), - initial_supply: DEFAULT_INITIAL_SUPPLY(), - contract_address_salt: SALT(), - is_unruggable: false - ); - println!("token_address ekubo launch: {:?}", token_address); - println!( - "Balance of launchpad: {:?}", - IERC20Dispatcher { contract_address: token_address } - .balance_of(launchpad.contract_address) - ); - let launch = launchpad.get_coin_launch(token_address); - let starting_price = i129 { sign: true, mag: 100_u128 }; - println!("Initial available: {:?}", launch.initial_available_supply); - let lp_meme_supply = launch.initial_available_supply - launch.available_supply; - println!("lp_meme_supply {:?}", lp_meme_supply); - let memecoin = IERC20Dispatcher { contract_address: token_address }; - start_cheat_caller_address(memecoin.contract_address, OWNER()); - // memecoin.transfer(launchpad.contract_address, DEFAULT_INITIAL_SUPPLY()); - memecoin.transfer(launchpad.contract_address, lp_meme_supply); - memecoin.approve(launchpad.contract_address, lp_meme_supply); - memecoin.approve(EKUBO_EXCHANGE_ADDRESS(), lp_meme_supply); - stop_cheat_caller_address(memecoin.contract_address); - - let params: EkuboLaunchParameters = EkuboLaunchParameters { - owner: launch.owner, - token_address: launch.token_address, - quote_address: launch.token_quote.token_address, - lp_supply: lp_meme_supply, - // lp_supply: launch.liquidity_raised, - pool_params: EkuboPoolParameters { - fee: 0xc49ba5e353f7d00000000000000000, - tick_spacing: 5982, - starting_price, - bound: 88719042, - } - }; - // start_cheat_caller_address(erc20.contract_address, OWNER()); - - // memecoin.transfer(FACTORY_ADDRESS(), DEFAULT_INITIAL_SUPPLY()); - let quote_token = IERC20Dispatcher { contract_address: erc20.contract_address }; - // erc20.transfer(launchpad.contract_address, launch.liquidity_raised); - start_cheat_caller_address(launchpad.contract_address, OWNER()); - println!("buy threshold liquidity"); - - run_buy_by_amount( - launchpad, quote_token, memecoin, THRESHOLD_LIQUIDITY, token_address, OWNER(), - ); - let balance_quote_launch = quote_token.balance_of(launchpad.contract_address); - println!("balance quote {:?}", balance_quote_launch); - - println!("add liquidity ekubo"); - // launchpad.add_liquidity_ekubo(token_address, params); - start_cheat_caller_address(launchpad.contract_address, OWNER()); - - launchpad.add_liquidity_ekubo(token_address); - stop_cheat_caller_address(launchpad.contract_address); - } - - - #[test] - #[fork("Mainnet")] - fn test_add_liquidity_jediswap() { - println!("try add liq jediswap"); - let (sender, erc20, launchpad) = request_fixture(); - start_cheat_caller_address(launchpad.contract_address, OWNER()); - let token_address = launchpad - .create_and_launch_token( - symbol: SYMBOL(), - name: NAME(), - initial_supply: DEFAULT_INITIAL_SUPPLY(), - contract_address_salt: SALT(), - is_unruggable: false - ); - println!("token_address ekubo launch: {:?}", token_address); - println!( - "Balance of launchpad: {:?}", - IERC20Dispatcher { contract_address: token_address } - .balance_of(launchpad.contract_address) - ); - let launch = launchpad.get_coin_launch(token_address); - let starting_price = i129 { sign: true, mag: 100_u128 }; - println!("Initial available: {:?}", launch.initial_available_supply); - let lp_meme_supply = launch.initial_available_supply - launch.available_supply; - println!("lp_meme_supply {:?}", lp_meme_supply); - let memecoin = IERC20Dispatcher { contract_address: token_address }; - start_cheat_caller_address(memecoin.contract_address, OWNER()); - // memecoin.transfer(launchpad.contract_address, DEFAULT_INITIAL_SUPPLY()); - memecoin.transfer(launchpad.contract_address, lp_meme_supply); - memecoin.approve(launchpad.contract_address, lp_meme_supply); - memecoin.approve(EKUBO_EXCHANGE_ADDRESS(), lp_meme_supply); - stop_cheat_caller_address(memecoin.contract_address); - - let quote_token = IERC20Dispatcher { contract_address: erc20.contract_address }; - start_cheat_caller_address(launchpad.contract_address, OWNER()); - println!("buy threshold liquidity"); - - run_buy_by_amount( - launchpad, quote_token, memecoin, THRESHOLD_LIQUIDITY, token_address, OWNER(), - ); - let balance_quote_launch = quote_token.balance_of(launchpad.contract_address); - println!("balance quote {:?}", balance_quote_launch); - - println!("add liquidity ekubo"); - // launchpad.add_liquidity_ekubo(token_address, params); - // launchpad.add_liquidity_ekubo(token_address); - launchpad.add_liquidity_jediswap(token_address); - - stop_cheat_caller_address(launchpad.contract_address); - } - - #[test] - #[fork("Mainnet")] - fn test_create_and_add_liquidity_unrug() { - let (b, quote_token, launchpad) = request_fixture(); - let starting_price = i129 { sign: true, mag: 4600158 }; // 0.01ETH/MEME - let quote_to_deposit = 215_000; - let factory = IFactoryDispatcher { contract_address: FACTORY_ADDRESS() }; - - let total_supply = DEFAULT_INITIAL_SUPPLY(); - // start_cheat_caller_address(launchpad.contract_address, OWNER()); - let token_address = launchpad - .create_unrug_token( - owner: launchpad.contract_address, - name: NAME(), - symbol: SYMBOL(), - initial_supply: DEFAULT_INITIAL_SUPPLY(), - contract_address_salt: SALT() + 1, - is_launch_bonding_now: true - ); - println!("token_address unrug: {:?}", token_address); - - start_cheat_caller_address(token_address, launchpad.contract_address); - - let memecoin = IERC20Dispatcher { contract_address: token_address }; - let mut balance_meme_launch = memecoin.balance_of(launchpad.contract_address); - println!("balance meme {:?}", balance_meme_launch); - - let mut balance_meme_launch_owner = memecoin.balance_of(OWNER()); - println!("balance meme owner {:?}", balance_meme_launch_owner); - - let mut balance_meme_launch_factory = memecoin.balance_of(FACTORY_ADDRESS()); - println!("balance factory {:?}", balance_meme_launch_factory); - - // memecoin.transfer(launchpad.contract_address, DEFAULT_INITIAL_SUPPLY()); - balance_meme_launch = memecoin.balance_of(launchpad.contract_address); - println!("balance meme {:?}", balance_meme_launch); - start_cheat_caller_address(memecoin.contract_address, OWNER()); - // memecoin.approve(launchpad.contract_address, total_supply); - // memecoin.transfer(launchpad.contract_address, total_supply); - - // stop_cheat_caller_address(token_address); - let launch = launchpad.get_coin_launch(token_address); - - // let total_token_holded: u256 = 1_000 * pow_256(10, 18); - let total_token_holded: u256 = launch.total_supply - launch.total_token_holded; - // let total_token_holded: u256 = 1_000; - - let launch_params = LaunchParameters { - memecoin_address: token_address, - transfer_restriction_delay: 100, - max_percentage_buy_launch: 200, // 2% - quote_address: quote_token.contract_address, - initial_holders: array![].span(), - initial_holders_amounts: array![].span(), - // initial_holders: array![launchpad.contract_address].span(), - // initial_holders_amounts: array![total_token_holded].span(), - }; - - let ekubo_pool_params = EkuboPoolParameters { - fee: 0xc49ba5e353f7d00000000000000000, - tick_spacing: 5982, - starting_price, - bound: 88719042 - }; - start_cheat_caller_address(launchpad.contract_address, OWNER()); - println!("buy liquidity threshold unrug"); - - run_buy_by_amount( - launchpad, quote_token, memecoin, THRESHOLD_LIQUIDITY, token_address, OWNER(), - ); - let balance_quote_launch = quote_token.balance_of(launchpad.contract_address); - println!("balance balance_quote_launch {:?}", balance_quote_launch); - println!("add liquidity unrug"); - let (id, position) = launchpad - .add_liquidity_unrug( - token_address, - launch_params, - EkuboPoolParameters { - fee: 0xc49ba5e353f7d00000000000000000, - tick_spacing: 5982, - starting_price, - bound: 88719042 - } - ); - // println!("id: {:?}", id); - - // let pool_key = PoolKey { - // token0: position.pool_key.token0, - // token1: position.pool_key.token1, - // fee: position.pool_key.fee.try_into().unwrap(), - // tick_spacing: position.pool_key.tick_spacing.try_into().unwrap(), - // extension: position.pool_key.extension - // }; - - // let core = ICoreDispatcher { contract_address: EKUBO_CORE() }; - // let liquidity = core.get_pool_liquidity(pool_key); - // let price = core.get_pool_price(pool_key); - // let reserve_memecoin = IERC20Dispatcher { contract_address: token_address } - // .balance_of(core.contract_address); - // let reserve_quote = IERC20Dispatcher { contract_address: quote_token.contract_address } - // .balance_of(core.contract_address); - // println!("Liquidity: {}", liquidity); - - } - - - #[test] - #[fork("Mainnet")] - fn test_create_and_add_liquidity_unrug_liq_without_launchpad_threshold() { - let (b, quote_token, launchpad) = request_fixture(); - let starting_price = i129 { sign: true, mag: 4600158 }; // 0.01ETH/MEME - let quote_to_deposit = 215_000; - let factory = IFactoryDispatcher { contract_address: FACTORY_ADDRESS() }; - - let total_supply = DEFAULT_INITIAL_SUPPLY(); - // start_cheat_caller_address(launchpad.contract_address, OWNER()); - let token_address = launchpad - .create_unrug_token( - owner: launchpad.contract_address, - name: NAME(), - symbol: SYMBOL(), - initial_supply: DEFAULT_INITIAL_SUPPLY(), - contract_address_salt: SALT() + 1, - is_launch_bonding_now: false - ); - println!("token_address unrug: {:?}", token_address); - - start_cheat_caller_address(token_address, launchpad.contract_address); - - let memecoin = IERC20Dispatcher { contract_address: token_address }; - let mut balance_meme_launch = memecoin.balance_of(launchpad.contract_address); - println!("balance meme {:?}", balance_meme_launch); - - let mut balance_meme_launch_owner = memecoin.balance_of(OWNER()); - println!("balance meme owner {:?}", balance_meme_launch_owner); - - let mut balance_meme_launch_factory = memecoin.balance_of(FACTORY_ADDRESS()); - println!("balance factory {:?}", balance_meme_launch_factory); - - // memecoin.transfer(launchpad.contract_address, DEFAULT_INITIAL_SUPPLY()); - balance_meme_launch = memecoin.balance_of(launchpad.contract_address); - println!("balance meme {:?}", balance_meme_launch); - start_cheat_caller_address(memecoin.contract_address, OWNER()); - // memecoin.approve(launchpad.contract_address, total_supply); - // memecoin.transfer(launchpad.contract_address, total_supply); - - // stop_cheat_caller_address(token_address); - let launch = launchpad.get_coin_launch(token_address); - let lp_meme_supply = launch.initial_available_supply - launch.available_supply; - - // let total_token_holded: u256 = 1_000 * pow_256(10, 18); - let total_token_holded: u256 = launch.total_supply - launch.total_token_holded; - // let total_token_holded: u256 = 1_000; - - let launch_params = LaunchParameters { - memecoin_address: token_address, - transfer_restriction_delay: 100, - max_percentage_buy_launch: 200, // 2% - quote_address: quote_token.contract_address, - initial_holders: array![].span(), - initial_holders_amounts: array![].span(), - // initial_holders: array![launchpad.contract_address].span(), - // initial_holders_amounts: array![total_token_holded].span(), - }; - - let ekubo_pool_params = EkuboPoolParameters { - fee: 0xc49ba5e353f7d00000000000000000, - tick_spacing: 5982, - starting_price, - bound: 88719042 - }; - start_cheat_caller_address(launchpad.contract_address, OWNER()); - println!("buy liquidity threshold unrug"); - - let erc20 = IERC20Dispatcher { contract_address: quote_token.contract_address }; - - erc20.transfer(launchpad.contract_address, quote_to_deposit); - // run_buy_by_amount( - // launchpad, quote_token, memecoin, THRESHOLD_LIQUIDITY, token_address, OWNER(), - // ); - let balance_quote_launch = quote_token.balance_of(launchpad.contract_address); - println!("balance balance_quote_launch {:?}", balance_quote_launch); - println!("add liquidity unrug"); - let (id, position) = launchpad - .add_liquidity_unrug_lp( - token_address, - quote_token.contract_address, - lp_meme_supply, - launch_params, - EkuboPoolParameters { - fee: 0xc49ba5e353f7d00000000000000000, - tick_spacing: 5982, - starting_price, - bound: 88719042 - } - ); - // println!("id: {:?}", id); - - // let pool_key = PoolKey { - // token0: position.pool_key.token0, - // token1: position.pool_key.token1, - // fee: position.pool_key.fee.try_into().unwrap(), - // tick_spacing: position.pool_key.tick_spacing.try_into().unwrap(), - // extension: position.pool_key.extension - // }; - - // let core = ICoreDispatcher { contract_address: EKUBO_CORE() }; - // let liquidity = core.get_pool_liquidity(pool_key); - // let price = core.get_pool_price(pool_key); - // let reserve_memecoin = IERC20Dispatcher { contract_address: token_address } - // .balance_of(core.contract_address); - // let reserve_quote = IERC20Dispatcher { contract_address: quote_token.contract_address } - // .balance_of(core.contract_address); - // println!("Liquidity: {}", liquidity); - - } - - - #[test] - #[fork("Mainnet")] - fn test_create_and_add_liquidity_unrug_liq_without_launchpad_but_launch() { - let (b, quote_token, launchpad) = request_fixture(); - let starting_price = i129 { sign: true, mag: 4600158 }; // 0.01ETH/MEME - let quote_to_deposit = 215_000; - let factory = IFactoryDispatcher { contract_address: FACTORY_ADDRESS() }; - - let total_supply = DEFAULT_INITIAL_SUPPLY(); - // start_cheat_caller_address(launchpad.contract_address, OWNER()); - let token_address = launchpad - .create_unrug_token( - owner: launchpad.contract_address, - name: NAME(), - symbol: SYMBOL(), - initial_supply: DEFAULT_INITIAL_SUPPLY(), - contract_address_salt: SALT() + 1, - is_launch_bonding_now: true - ); - println!("token_address unrug: {:?}", token_address); - - start_cheat_caller_address(token_address, launchpad.contract_address); - - let memecoin = IERC20Dispatcher { contract_address: token_address }; - let mut balance_meme_launch = memecoin.balance_of(launchpad.contract_address); - println!("balance meme {:?}", balance_meme_launch); - - let mut balance_meme_launch_owner = memecoin.balance_of(OWNER()); - println!("balance meme owner {:?}", balance_meme_launch_owner); - - let mut balance_meme_launch_factory = memecoin.balance_of(FACTORY_ADDRESS()); - println!("balance factory {:?}", balance_meme_launch_factory); - - // memecoin.transfer(launchpad.contract_address, DEFAULT_INITIAL_SUPPLY()); - balance_meme_launch = memecoin.balance_of(launchpad.contract_address); - println!("balance meme {:?}", balance_meme_launch); - start_cheat_caller_address(memecoin.contract_address, OWNER()); - // memecoin.approve(launchpad.contract_address, total_supply); - // memecoin.transfer(launchpad.contract_address, total_supply); - - // stop_cheat_caller_address(token_address); - let launch = launchpad.get_coin_launch(token_address); - - let lp_meme_supply = DEFAULT_INITIAL_SUPPLY() / 5; - - // let total_token_holded: u256 = 1_000 * pow_256(10, 18); - // let total_token_holded: u256 = launch.total_supply - launch.total_token_holded; - let total_token_holded: u256 = lp_meme_supply / 10; - // let total_token_holded: u256 = 1_000; - - let launch_params = LaunchParameters { - memecoin_address: token_address, - transfer_restriction_delay: 100, - max_percentage_buy_launch: 200, // 2% - quote_address: quote_token.contract_address, - initial_holders: array![].span(), - initial_holders_amounts: array![].span(), - // initial_holders: array![launchpad.contract_address].span(), - // initial_holders_amounts: array![total_token_holded].span(), - }; - - let ekubo_pool_params = EkuboPoolParameters { - fee: 0xc49ba5e353f7d00000000000000000, - tick_spacing: 5982, - starting_price, - bound: 88719042 - }; - start_cheat_caller_address(launchpad.contract_address, OWNER()); - println!("buy liquidity threshold unrug"); - - run_buy_by_amount( - launchpad, quote_token, memecoin, THRESHOLD_LIQUIDITY, token_address, OWNER(), - ); - let balance_quote_launch = quote_token.balance_of(launchpad.contract_address); - println!("balance balance_quote_launch {:?}", balance_quote_launch); - println!("add liquidity unrug"); - let (id, position) = launchpad - .add_liquidity_unrug_lp( - token_address, - quote_token.contract_address, - lp_meme_supply, - launch_params, - EkuboPoolParameters { - fee: 0xc49ba5e353f7d00000000000000000, - tick_spacing: 5982, - starting_price, - bound: 88719042 - } - ); - // println!("id: {:?}", id); - - // let pool_key = PoolKey { - // token0: position.pool_key.token0, - // token1: position.pool_key.token1, - // fee: position.pool_key.fee.try_into().unwrap(), - // tick_spacing: position.pool_key.tick_spacing.try_into().unwrap(), - // extension: position.pool_key.extension - // }; - - // let core = ICoreDispatcher { contract_address: EKUBO_CORE() }; - // let liquidity = core.get_pool_liquidity(pool_key); - // let price = core.get_pool_price(pool_key); - // let reserve_memecoin = IERC20Dispatcher { contract_address: token_address } - // .balance_of(core.contract_address); - // let reserve_quote = IERC20Dispatcher { contract_address: quote_token.contract_address } - // .balance_of(core.contract_address); - // println!("Liquidity: {}", liquidity); - - } - - - #[test] - #[should_panic(expected: ('Caller is missing role',))] - fn test_set_token_with_non_admin() { - let (_, erc20, launchpad) = request_fixture(); - - let expected_token = TokenQuoteBuyCoin { - token_address: erc20.contract_address, - starting_price: INITIAL_KEY_PRICE, - price: INITIAL_KEY_PRICE, - is_enable: true, - step_increase_linear: STEP_LINEAR_INCREASE, - }; - - start_cheat_caller_address(launchpad.contract_address, ALICE()); - launchpad.set_token(expected_token); - } - - #[test] - #[should_panic(expected: ('protocol_fee_too_high',))] - fn test_set_protocol_fee_percent_too_high() { - let (_, _, launchpad) = request_fixture(); - - launchpad.set_protocol_fee_percent(MAX_FEE_PROTOCOL + 1); - } - - #[test] - #[should_panic(expected: ('protocol_fee_too_low',))] - fn test_set_protocol_fee_percent_too_low() { - let (_, _, launchpad) = request_fixture(); - - launchpad.set_protocol_fee_percent(MIN_FEE_PROTOCOL - 1); - } - - #[test] - #[should_panic(expected: ('Caller is missing role',))] - fn test_set_protocol_fee_percent_non_admin() { - let (_, _, launchpad) = request_fixture(); - - launchpad.set_protocol_fee_percent(MID_FEE_PROTOCOL); - } - - #[test] - fn test_set_protocol_fee_ok() { - let (sender_address, _, launchpad) = request_fixture(); - start_cheat_caller_address(launchpad.contract_address, sender_address); - - launchpad.set_protocol_fee_percent(MID_FEE_PROTOCOL); - } - - #[test] - #[should_panic(expected: ('creator_fee_too_low',))] - fn test_set_creator_fee_percent_too_low() { - let (sender_address, _, launchpad) = request_fixture(); - start_cheat_caller_address(launchpad.contract_address, sender_address); - - launchpad.set_creator_fee_percent(MIN_FEE_CREATOR - 1); - } - - #[test] - #[should_panic(expected: ('creator_fee_too_high',))] - fn test_set_creator_fee_percent_too_high() { - let (sender_address, _, launchpad) = request_fixture(); - start_cheat_caller_address(launchpad.contract_address, sender_address); - - launchpad.set_creator_fee_percent(MAX_FEE_CREATOR + 1); - } - - #[test] - #[should_panic(expected: ('Caller is missing role',))] - fn test_set_creator_fee_percent_non_admin() { - let (_, _, launchpad) = request_fixture(); - start_cheat_caller_address(launchpad.contract_address, ALICE()); - - launchpad.set_creator_fee_percent(MID_FEE_PROTOCOL); - } - - #[test] - fn test_set_creator_fee_percent_ok() { - let (sender_address, _, launchpad) = request_fixture(); - start_cheat_caller_address(launchpad.contract_address, sender_address); - - launchpad.set_creator_fee_percent(MID_FEE_CREATOR); - } - - #[test] - #[should_panic(expected: ('Caller is missing role',))] - fn test_set_dollar_paid_coin_creation_non_admin() { - let (_, _, launchpad) = request_fixture(); - start_cheat_caller_address(launchpad.contract_address, ALICE()); - - launchpad.set_dollar_paid_coin_creation(50_u256); - } - - #[test] - fn test_set_dollar_paid_coin_creation_ok() { - let (sender_address, _, launchpad) = request_fixture(); - start_cheat_caller_address(launchpad.contract_address, sender_address); +// #[cfg(test)] +// mod launchpad_tests { +// use afk::interfaces::factory::{IFactory, IFactoryDispatcher, IFactoryDispatcherTrait}; +// use afk::launchpad::launchpad::LaunchpadMarketplace::{Event as LaunchpadEvent}; +// use afk::launchpad::launchpad::{ +// ILaunchpadMarketplaceDispatcher, ILaunchpadMarketplaceDispatcherTrait, +// }; +// use afk::tokens::erc20::{IERC20, IERC20Dispatcher, IERC20DispatcherTrait}; +// use afk::tokens::memecoin::{IMemecoin, IMemecoinDispatcher, IMemecoinDispatcherTrait}; +// use afk::types::launchpad_types::{ +// CreateToken, TokenQuoteBuyCoin, BondingType, CreateLaunch, SetJediswapNFTRouterV2, +// SetJediswapV2Factory, SupportedExchanges, EkuboLP, EkuboPoolParameters, TokenLaunch, +// EkuboLaunchParameters, LaunchParameters +// }; + +// use core::num::traits::Zero; +// use core::traits::Into; +// use ekubo::interfaces::core::{ICore, ICoreDispatcher, ICoreDispatcherTrait}; +// use ekubo::interfaces::positions::{IPositionsDispatcher, IPositionsDispatcherTrait}; +// use ekubo::interfaces::token_registry::{ +// ITokenRegistryDispatcher, ITokenRegistryDispatcherTrait, +// }; + +// use ekubo::types::i129::i129; +// use ekubo::types::keys::PoolKey; +// use openzeppelin::utils::serde::SerializedAppend; +// use snforge_std::{ +// declare, ContractClass, ContractClassTrait, spy_events, start_cheat_caller_address, +// start_cheat_caller_address_global, stop_cheat_caller_address, +// stop_cheat_caller_address_global, start_cheat_block_timestamp, DeclareResultTrait, +// EventSpyAssertionsTrait +// }; +// use starknet::syscalls::call_contract_syscall; + +// use starknet::{ContractAddress, ClassHash, class_hash::class_hash_const}; + +// // fn DEFAULT_INITIAL_SUPPLY() -> u256 { +// // // 21_000_000 * pow_256(10, 18) +// // 100_000_000 +// // // * pow_256(10, 18) +// // } +// fn DEFAULT_INITIAL_SUPPLY() -> u256 { +// // 21_000_000 * pow_256(10, 18) +// 100 +// // * pow_256(10, 18) +// } + +// // const INITIAL_KEY_PRICE:u256=1/100; +// const INITIAL_SUPPLY_DEFAULT: u256 = 100_000_000; +// const INITIAL_KEY_PRICE: u256 = 1; +// const STEP_LINEAR_INCREASE: u256 = 1; +// const THRESHOLD_LIQUIDITY: u256 = 10; +// const THRESHOLD_MARKET_CAP: u256 = 500; +// const MIN_FEE_PROTOCOL: u256 = 10; //0.1% +// const MAX_FEE_PROTOCOL: u256 = 1000; //10% +// const MID_FEE_PROTOCOL: u256 = 100; //1% +// const MIN_FEE_CREATOR: u256 = 100; //1% +// const MID_FEE_CREATOR: u256 = 1000; //10% +// const MAX_FEE_CREATOR: u256 = 5000; //50% +// // const INITIAL_KEY_PRICE: u256 = 1 / 10_000; +// // const THRESHOLD_LIQUIDITY: u256 = 10; +// // const THRESHOLD_LIQUIDITY: u256 = 10_000; + +// const RATIO_SUPPLY_LAUNCH: u256 = 5; +// const LIQUIDITY_SUPPLY: u256 = INITIAL_SUPPLY_DEFAULT / RATIO_SUPPLY_LAUNCH; +// const BUYABLE: u256 = INITIAL_SUPPLY_DEFAULT / RATIO_SUPPLY_LAUNCH; + +// const LIQUIDITY_RATIO: u256 = 5; + +// fn FACTORY_ADDRESS() -> ContractAddress { +// 0x01a46467a9246f45c8c340f1f155266a26a71c07bd55d36e8d1c7d0d438a2dbc.try_into().unwrap() +// } + +// fn EKUBO_EXCHANGE_ADDRESS() -> ContractAddress { +// 0x00000005dd3d2f4429af886cd1a3b08289dbcea99a294197e9eb43b0e0325b4b.try_into().unwrap() +// } + +// // fn EKUBO_EXCHANGE_ADDRESS() -> ContractAddress { +// // 0x02bd1cdd5f7f17726ae221845afd9580278eebc732bc136fe59d5d94365effd5.try_into().unwrap() +// // } + +// fn EKUBO_CORE() -> ContractAddress { +// 0x00000005dd3d2f4429af886cd1a3b08289dbcea99a294197e9eb43b0e0325b4b.try_into().unwrap() +// } + +// fn EKUBO_POSITIONS() -> ContractAddress { +// 0x02e0af29598b407c8716b17f6d2795eca1b471413fa03fb145a5e33722184067.try_into().unwrap() +// } + +// fn EKUBO_REGISTRY() -> ContractAddress { +// 0x0013e25867b6eef62703735aa4cfa7754e72f4e94a56c9d3d9ad8ebe86cee4aa.try_into().unwrap() +// } + +// fn JEDISWAP_FACTORY() -> ContractAddress { +// 0x01aa950c9b974294787de8df8880ecf668840a6ab8fa8290bf2952212b375148.try_into().unwrap() +// } + +// fn JEDISWAP_NFT_V2() -> ContractAddress { +// 0x0469b656239972a2501f2f1cd71bf4e844d64b7cae6773aa84c702327c476e5b.try_into().unwrap() +// } + + +// fn SALT() -> felt252 { +// 'salty'.try_into().unwrap() +// } + +// // Constants +// fn OWNER() -> ContractAddress { +// // 'owner'.try_into().unwrap() +// 123.try_into().unwrap() +// } + +// fn RECIPIENT() -> ContractAddress { +// 'recipient'.try_into().unwrap() +// } + +// fn SPENDER() -> ContractAddress { +// 'spender'.try_into().unwrap() +// } + +// fn ALICE() -> ContractAddress { +// 'alice'.try_into().unwrap() +// } + +// fn BOB() -> ContractAddress { +// 'bob'.try_into().unwrap() +// } + +// fn NAME() -> felt252 { +// 'name'.try_into().unwrap() +// } + +// fn SYMBOL() -> felt252 { +// 'symbol'.try_into().unwrap() +// } + +// // Math +// fn pow_256(self: u256, mut exponent: u8) -> u256 { +// if self.is_zero() { +// return 0; +// } +// let mut result = 1; +// let mut base = self; + +// loop { +// if exponent & 1 == 1 { +// result = result * base; +// } + +// exponent = exponent / 2; +// if exponent == 0 { +// break result; +// } + +// base = base * base; +// } +// } + +// // Declare and create all contracts +// // Return sender_address, Erc20 quote and Launchpad contract +// fn request_fixture() -> (ContractAddress, IERC20Dispatcher, ILaunchpadMarketplaceDispatcher) { +// // println!("request_fixture"); +// let erc20_class = declare_erc20(); +// let meme_class = declare_memecoin(); +// let launch_class = declare_launchpad(); +// request_fixture_custom_classes(*erc20_class, *meme_class, *launch_class) +// } + +// fn request_fixture_custom_classes( +// erc20_class: ContractClass, meme_class: ContractClass, launch_class: ContractClass +// ) -> (ContractAddress, IERC20Dispatcher, ILaunchpadMarketplaceDispatcher) { +// let sender_address: ContractAddress = 123.try_into().unwrap(); +// let erc20 = deploy_erc20(erc20_class, 'USDC token', 'USDC', 1_000_000, sender_address); +// let token_address = erc20.contract_address.clone(); +// let launchpad = deploy_launchpad( +// launch_class, +// sender_address, +// token_address.clone(), +// INITIAL_KEY_PRICE, +// STEP_LINEAR_INCREASE, +// meme_class.class_hash, +// THRESHOLD_LIQUIDITY, +// THRESHOLD_MARKET_CAP, +// FACTORY_ADDRESS(), +// EKUBO_REGISTRY(), +// EKUBO_CORE(), +// EKUBO_POSITIONS(), +// EKUBO_EXCHANGE_ADDRESS() +// // ITokenRegistryDispatcher { contract_address: EKUBO_REGISTRY() }, +// // ICoreDispatcher { contract_address: EKUBO_CORE() }, +// // IPositionsDispatcher { contract_address: EKUBO_POSITIONS() }, +// ); +// // let launchpad = deploy_launchpad( +// // launch_class, +// // sender_address, +// // token_address.clone(), +// // INITIAL_KEY_PRICE * pow_256(10,18), +// // // INITIAL_KEY_PRICE, +// // // STEP_LINEAR_INCREASE, +// // STEP_LINEAR_INCREASE * pow_256(10,18), +// // erc20_class.class_hash, +// // THRESHOLD_LIQUIDITY * pow_256(10,18), +// // // THRESHOLD_LIQUIDITY, +// // THRESHOLD_MARKET_CAP * pow_256(10,18), +// // // THRESHOLD_MARKET_CAP +// // ); + +// start_cheat_caller_address(launchpad.contract_address, OWNER()); +// launchpad.set_address_jediswap_factory_v2(JEDISWAP_FACTORY()); +// launchpad.set_address_jediswap_nft_router_v2(JEDISWAP_NFT_V2()); +// (sender_address, erc20, launchpad) +// } + +// fn deploy_launchpad( +// class: ContractClass, +// admin: ContractAddress, +// token_address: ContractAddress, +// initial_key_price: u256, +// step_increase_linear: u256, +// coin_class_hash: ClassHash, +// threshold_liquidity: u256, +// threshold_marketcap: u256, +// factory_address: ContractAddress, +// ekubo_registry: ContractAddress, +// core: ContractAddress, +// positions: ContractAddress, +// ekubo_exchange_address: ContractAddress, +// // ekubo_registry: ITokenRegistryDispatcher, +// // core: ICoreDispatcher, +// // positions: IPositionsDispatcher, +// ) -> ILaunchpadMarketplaceDispatcher { +// // println!("deploy marketplace"); +// let mut calldata = array![admin.into()]; +// calldata.append_serde(initial_key_price); +// calldata.append_serde(token_address); +// calldata.append_serde(step_increase_linear); +// calldata.append_serde(coin_class_hash); +// calldata.append_serde(threshold_liquidity); +// calldata.append_serde(threshold_marketcap); +// calldata.append_serde(factory_address); +// calldata.append_serde(ekubo_registry); +// calldata.append_serde(core); +// calldata.append_serde(positions); +// calldata.append_serde(ekubo_exchange_address); +// let (contract_address, _) = class.deploy(@calldata).unwrap(); +// ILaunchpadMarketplaceDispatcher { contract_address } +// } + +// fn declare_launchpad() -> @ContractClass { +// declare("LaunchpadMarketplace").unwrap().contract_class() +// } + +// fn declare_erc20() -> @ContractClass { +// declare("ERC20").unwrap().contract_class() +// } + +// fn declare_memecoin() -> @ContractClass { +// declare("Memecoin").unwrap().contract_class() +// } + + +// fn deploy_erc20( +// class: ContractClass, +// name: felt252, +// symbol: felt252, +// initial_supply: u256, +// recipient: ContractAddress +// ) -> IERC20Dispatcher { +// let mut calldata = array![]; + +// name.serialize(ref calldata); +// symbol.serialize(ref calldata); +// (2 * initial_supply).serialize(ref calldata); +// recipient.serialize(ref calldata); +// 18_u8.serialize(ref calldata); + +// let (contract_address, _) = class.deploy(@calldata).unwrap(); + +// IERC20Dispatcher { contract_address } +// } + + +// fn run_buy_by_amount( +// launchpad: ILaunchpadMarketplaceDispatcher, +// erc20: IERC20Dispatcher, +// memecoin: IERC20Dispatcher, +// amount_quote: u256, +// token_address: ContractAddress, +// sender_address: ContractAddress, +// ) { +// start_cheat_caller_address(erc20.contract_address, sender_address); +// erc20.approve(launchpad.contract_address, amount_quote); +// let allowance = erc20.allowance(sender_address, launchpad.contract_address); +// // println!("test allowance erc20 {}", allowance); +// stop_cheat_caller_address(erc20.contract_address); + +// start_cheat_caller_address(launchpad.contract_address, sender_address); +// println!("buy coin {:?}", amount_quote,); +// // launchpad.buy_coin_by_quote_amount(token_address, amount_quote, Option::None); +// launchpad.buy_coin_by_quote_amount(token_address, amount_quote); +// stop_cheat_caller_address(launchpad.contract_address); +// } + + +// fn run_sell_by_amount( +// launchpad: ILaunchpadMarketplaceDispatcher, +// erc20: IERC20Dispatcher, +// memecoin: IERC20Dispatcher, +// amount_quote: u256, +// token_address: ContractAddress, +// sender_address: ContractAddress, +// ) { +// println!("sell coin for amount quote{:?}", amount_quote); +// let allowance = memecoin.allowance(sender_address, launchpad.contract_address); +// println!("test allowance meme coin{}", allowance); +// launchpad.sell_coin(token_address, amount_quote); +// } + +// fn run_calculation( +// launchpad: ILaunchpadMarketplaceDispatcher, +// amount_quote: u256, +// token_address: ContractAddress, +// sender_address: ContractAddress, +// is_decreased: bool, +// is_quote_amount: bool +// ) -> u256 { +// start_cheat_caller_address(launchpad.contract_address, sender_address); +// println!("calcul amount"); +// let amount = launchpad +// .get_coin_amount_by_quote_amount(token_address, amount_quote, is_decreased); +// println!("amount to receive {:?}", amount); +// amount +// } + +// fn calculate_slope(total_supply: u256) -> u256 { +// let liquidity_supply = total_supply / LIQUIDITY_RATIO; +// let liquidity_available = total_supply - liquidity_supply; +// let slope = (2 * THRESHOLD_LIQUIDITY) / (liquidity_available * (liquidity_available - 1)); +// slope +// } + +// #[test] +// #[fork("Mainnet")] +// fn launchpad_buy_all() { +// println!("launchpad_buy_all"); +// let (sender_address, erc20, launchpad) = request_fixture(); +// start_cheat_caller_address_global(sender_address); +// start_cheat_caller_address(erc20.contract_address, sender_address); +// let mut spy = spy_events(); + +// // Call a view function of the contract +// // Check default token used +// let default_token = launchpad.get_default_token(); +// assert(default_token.token_address == erc20.contract_address, 'no default token'); +// assert(default_token.starting_price == INITIAL_KEY_PRICE, 'no init price'); +// start_cheat_caller_address(launchpad.contract_address, sender_address); +// println!("create and launch token"); +// let token_address = launchpad +// .create_and_launch_token( +// // owner: OWNER(), +// symbol: SYMBOL(), +// name: NAME(), +// initial_supply: DEFAULT_INITIAL_SUPPLY(), +// contract_address_salt: SALT(), +// is_unruggable: false +// ); +// println!("test token_address {:?}", token_address); +// let memecoin = IERC20Dispatcher { contract_address: token_address }; + +// // All buy +// // run_buy_by_amount( +// // launchpad, erc20, memecoin, THRESHOLD_LIQUIDITY, token_address, sender_address, +// // ); +// println!("first buy {:?}", token_address); + +// run_buy_by_amount( +// launchpad, erc20, memecoin, THRESHOLD_LIQUIDITY - 1, token_address, sender_address, +// ); - launchpad.set_dollar_paid_coin_creation(50_u256); - } - - - #[test] - #[should_panic(expected: ('Caller is missing role',))] - fn test_set_dollar_paid_launch_creation_non_admin() { - let (_, _, launchpad) = request_fixture(); - start_cheat_caller_address(launchpad.contract_address, ALICE()); - - launchpad.set_dollar_paid_launch_creation(50_u256); - } - - #[test] - fn test_set_dollar_paid_launch_creation_ok() { - let (sender_address, _, launchpad) = request_fixture(); - start_cheat_caller_address(launchpad.contract_address, sender_address); +// run_buy_by_amount(launchpad, erc20, memecoin, 1, token_address, sender_address,); + +// // let expected_launch_token_event = LaunchpadEvent::CreateLaunch( +// // CreateLaunch { +// // caller: OWNER(), +// // token_address: token_address, +// // amount: 0, +// // price: INITIAL_KEY_PRICE, +// // total_supply: DEFAULT_INITIAL_SUPPLY(), +// // slope: slope, +// // threshold_liquidity: THRESHOLD_LIQUIDITY, +// // quote_token_address: erc20.contract_address, +// // } +// // ); +// // spy.assert_emitted(@array![(launchpad.contract_address, expected_launch_token_event)]); +// let launched_token = launchpad.get_coin_launch(token_address); +// let default_supply = DEFAULT_INITIAL_SUPPLY(); +// // assert(launched_token.owner == OWNER(), 'wrong owner'); +// assert(launched_token.token_address == token_address, 'wrong token address'); +// assert(launched_token.total_supply == DEFAULT_INITIAL_SUPPLY(), 'wrong initial supply'); +// assert( +// launched_token.bonding_curve_type.unwrap() == BondingType::Linear, 'wrong type curve' +// ); +// assert(launched_token.liquidity_raised == THRESHOLD_LIQUIDITY, 'wrong liq raised'); +// assert(launched_token.initial_pool_supply == default_supply / 5_u256, 'wrong init pool'); +// // assert( +// // launched_token.total_token_holded >= default_supply +// // - launched_token.initial_pool_supply, +// // 'wrong token holded' +// // ); +// assert( +// launched_token.token_quote.token_address == erc20.contract_address, 'wrong token quote' +// ); +// } + +// #[test] +// #[fork("Mainnet")] +// fn launchpad_end_to_end() { +// println!("launchpad_end_to_end"); +// let (sender_address, erc20, launchpad) = request_fixture(); +// start_cheat_caller_address_global(sender_address); +// start_cheat_caller_address(erc20.contract_address, sender_address); +// let mut spy = spy_events(); + +// // Call a view function of the contract +// // Check default token used +// let default_token = launchpad.get_default_token(); +// assert(default_token.token_address == erc20.contract_address, 'no default token'); +// assert(default_token.starting_price == INITIAL_KEY_PRICE, 'no init price'); +// start_cheat_caller_address(launchpad.contract_address, sender_address); +// println!("create and launch token"); +// let token_address = launchpad +// .create_and_launch_token( +// // owner: OWNER(), +// symbol: SYMBOL(), +// name: NAME(), +// initial_supply: DEFAULT_INITIAL_SUPPLY(), +// contract_address_salt: SALT(), +// is_unruggable: false +// ); +// println!("test token_address {:?}", token_address); +// let memecoin = IERC20Dispatcher { contract_address: token_address }; + +// run_buy_by_amount(launchpad, erc20, memecoin, 1, token_address, sender_address,); + +// run_sell_by_amount(launchpad, erc20, memecoin, 1, token_address, sender_address,); +// // All buy + +// run_buy_by_amount( +// launchpad, erc20, memecoin, THRESHOLD_LIQUIDITY, token_address, sender_address, +// ); +// // let expected_launch_token_event = LaunchpadEvent::CreateLaunch( +// // CreateLaunch { +// // caller: OWNER(), +// // token_address: token_address, +// // amount: 0, +// // price: initial_key_price, +// // total_supply: DEFAULT_INITIAL_SUPPLY(), +// // slope: slope, +// // threshold_liquidity: THRESHOLD_LIQUIDITY, +// // quote_token_address: erc20.contract_address, +// // } +// // ); +// // spy.assert_emitted(@array![(launchpad.contract_address, expected_launch_token_event)]); +// let launched_token = launchpad.get_coin_launch(token_address); +// let default_supply = DEFAULT_INITIAL_SUPPLY(); +// // assert(launched_token.owner == OWNER(), 'wrong owner'); +// assert(launched_token.token_address == token_address, 'wrong token address'); +// assert(launched_token.total_supply == DEFAULT_INITIAL_SUPPLY(), 'wrong initial supply'); +// assert( +// launched_token.bonding_curve_type.unwrap() == BondingType::Linear, 'wrong type curve' +// ); +// assert(launched_token.liquidity_raised == THRESHOLD_LIQUIDITY, 'wrong liq raised'); +// assert(launched_token.initial_pool_supply == default_supply / 5_u256, 'wrong init pool'); +// assert( +// launched_token.total_token_holded >= default_supply +// - launched_token.initial_pool_supply, +// 'wrong token holded' +// ); +// assert( +// launched_token.token_quote.token_address == erc20.contract_address, +// 'wrong token +// quote' +// ); +// } + +// #[test] +// #[fork("Mainnet")] +// fn launchpad_integration() { +// println!("launchpad_integration"); + +// let (sender_address, erc20, launchpad) = request_fixture(); +// start_cheat_caller_address_global(sender_address); +// start_cheat_caller_address(erc20.contract_address, sender_address); +// let default_token = launchpad.get_default_token(); +// assert(default_token.token_address == erc20.contract_address, 'no default token'); +// assert(default_token.starting_price == INITIAL_KEY_PRICE, 'no init price'); +// start_cheat_caller_address(launchpad.contract_address, sender_address); + +// let token_address = launchpad +// .create_token( +// recipient: OWNER(), +// // owner: OWNER(), +// symbol: SYMBOL(), +// name: NAME(), +// initial_supply: DEFAULT_INITIAL_SUPPLY(), +// contract_address_salt: SALT(), +// is_unruggable: false, +// ); +// // println!("test token_address {:?}", token_address); +// let memecoin = IERC20Dispatcher { contract_address: token_address }; +// start_cheat_caller_address(memecoin.contract_address, OWNER()); + +// let balance_contract = memecoin.balance_of(launchpad.contract_address); +// println!("test balance_contract {:?}", balance_contract); + +// let total_supply = memecoin.total_supply(); +// // println!(" memecoin total_supply {:?}", total_supply); +// memecoin.approve(launchpad.contract_address, total_supply); + +// // let allowance = memecoin.allowance(sender_address, launchpad.contract_address); +// // println!("test allowance meme coin{}", allowance); +// // memecoin.transfer(launchpad.contract_address, total_supply); +// stop_cheat_caller_address(memecoin.contract_address); + +// start_cheat_caller_address(launchpad.contract_address, sender_address); + +// launchpad.launch_token(token_address); +// let amount_first_buy = 1_u256; + +// run_buy_by_amount( +// launchpad, erc20, memecoin, amount_first_buy, token_address, sender_address, +// ); - launchpad.set_dollar_paid_launch_creation(50_u256); - } - - - #[test] - #[should_panic(expected: ('Caller is missing role',))] - fn test_set_dollar_paid_finish_percentage_non_admin() { - let (_, _, launchpad) = request_fixture(); - start_cheat_caller_address(launchpad.contract_address, ALICE()); - - launchpad.set_dollar_paid_finish_percentage(50_u256); - } +// // let mut total_amount_buy = amount_first_buy; +// let mut amount_second = 1_u256; +// run_buy_by_amount( +// launchpad, erc20, memecoin, amount_second, token_address, sender_address, +// ); - #[test] - fn test_set_dollar_paid_finish_percentage_ok() { - let (sender_address, _, launchpad) = request_fixture(); - start_cheat_caller_address(launchpad.contract_address, sender_address); - - launchpad.set_dollar_paid_finish_percentage(50_u256); - } +// // let mut total_amount_buy = amount_first_buy; +// let mut last_amount = 8_u256; +// run_buy_by_amount(launchpad, erc20, memecoin, last_amount, token_address, sender_address,); +// } + + +// #[test] +// fn test_create_token() { +// let (_, _, launchpad) = request_fixture(); +// let mut spy = spy_events(); + +// start_cheat_caller_address(launchpad.contract_address, OWNER()); + +// let token_address = launchpad +// .create_token( +// recipient: OWNER(), +// symbol: SYMBOL(), +// name: NAME(), +// initial_supply: DEFAULT_INITIAL_SUPPLY(), +// contract_address_salt: SALT(), +// is_unruggable: false, +// ); + +// let expected_event = LaunchpadEvent::CreateToken( +// CreateToken { +// caller: OWNER(), +// token_address: token_address, +// symbol: SYMBOL(), +// name: NAME(), +// initial_supply: DEFAULT_INITIAL_SUPPLY(), +// total_supply: DEFAULT_INITIAL_SUPPLY(), +// is_unruggable: false +// } +// ); +// spy.assert_emitted(@array![(launchpad.contract_address, expected_event)]); +// } + +// // #[test] +// // #[fork("Mainnet")] +// // fn test_create_and_launch_token() { +// // let (_, erc20, launchpad) = request_fixture(); +// // let mut spy = spy_events(); +// // let initial_key_price = THRESHOLD_LIQUIDITY / DEFAULT_INITIAL_SUPPLY(); +// // let slope = calculate_slope(DEFAULT_INITIAL_SUPPLY()); + +// // start_cheat_caller_address(launchpad.contract_address, OWNER()); + +// // let token_address = launchpad +// // .create_and_launch_token( +// // symbol: SYMBOL(), +// // name: NAME(), +// // initial_supply: DEFAULT_INITIAL_SUPPLY(), +// // contract_address_salt: SALT(), +// // ); + +// // let create_token_event = LaunchpadEvent::CreateToken( +// // CreateToken { +// // caller: OWNER(), +// // token_address: token_address, +// // symbol: SYMBOL(), +// // name: NAME(), +// // initial_supply: DEFAULT_INITIAL_SUPPLY(), +// // total_supply: DEFAULT_INITIAL_SUPPLY(), +// // } +// // ); + +// // let launch_token_event = LaunchpadEvent::CreateLaunch( +// // CreateLaunch { +// // caller: OWNER(), +// // token_address: token_address, +// // amount: 0, +// // price: initial_key_price, +// // total_supply: DEFAULT_INITIAL_SUPPLY(), +// // slope: slope, +// // threshold_liquidity: THRESHOLD_LIQUIDITY, +// // quote_token_address: erc20.contract_address, +// // is_unruggable:false +// // } +// // ); + +// // spy +// // .assert_emitted( +// // @array![ +// // (launchpad.contract_address, create_token_event), +// // (launchpad.contract_address, launch_token_event) +// // ] +// // ); +// // } + +// #[test] +// // #[fork("Mainnet")] +// #[should_panic(expected: ('not launch',))] +// fn test_launch_token_with_uncreated_token() { +// let (_, erc20, launchpad) = request_fixture(); + +// launchpad.launch_token(coin_address: erc20.contract_address); +// } + +// #[test] +// // #[fork("Mainnet")] +// #[should_panic(expected: ('no supply provided',))] +// fn test_launch_token_with_no_supply_provided() { +// let (_, _, launchpad) = request_fixture(); + +// start_cheat_caller_address(launchpad.contract_address, OWNER()); + +// let token_address = launchpad +// .create_token( +// recipient: OWNER(), +// symbol: SYMBOL(), +// name: NAME(), +// initial_supply: DEFAULT_INITIAL_SUPPLY(), +// contract_address_salt: SALT(), +// is_unruggable: false, +// ); + +// launchpad.launch_token(coin_address: token_address); +// } + +// #[test] +// // #[fork("Mainnet")] +// fn test_launch_token() { +// let (_, erc20, launchpad) = request_fixture(); +// let mut spy = spy_events(); +// let starting_price = THRESHOLD_LIQUIDITY / DEFAULT_INITIAL_SUPPLY(); +// let slope = calculate_slope(DEFAULT_INITIAL_SUPPLY()); + +// start_cheat_caller_address(launchpad.contract_address, OWNER()); + +// let token_address = launchpad +// .create_token( +// recipient: launchpad.contract_address, +// symbol: SYMBOL(), +// name: NAME(), +// initial_supply: DEFAULT_INITIAL_SUPPLY(), +// contract_address_salt: SALT(), +// is_unruggable: false, +// ); + +// launchpad.launch_token(coin_address: token_address); + +// let expected_launch_token_event = LaunchpadEvent::CreateLaunch( +// CreateLaunch { +// caller: OWNER(), +// token_address: token_address, +// amount: 0, +// price: starting_price, +// total_supply: DEFAULT_INITIAL_SUPPLY(), +// slope: slope, +// threshold_liquidity: THRESHOLD_LIQUIDITY, +// quote_token_address: erc20.contract_address, +// is_unruggable: false, +// } +// ); - #[test] - #[should_panic(expected: ('Caller is missing role',))] - fn test_set_threshold_liquidity_non_admin() { - let (_, _, launchpad) = request_fixture(); - start_cheat_caller_address(launchpad.contract_address, ALICE()); - - launchpad.set_threshold_liquidity(50_u256); - } +// spy.assert_emitted(@array![(launchpad.contract_address, expected_launch_token_event)]); +// } - #[test] - fn test_set_threshold_liquidity_ok() { - let (sender_address, _, launchpad) = request_fixture(); - start_cheat_caller_address(launchpad.contract_address, sender_address); - - launchpad.set_threshold_liquidity(50_u256); - } - #[test] - #[should_panic(expected: ('Caller is missing role',))] - fn test_set_address_jediswap_factory_v2_non_admin() { - let (_, _, launchpad) = request_fixture(); - start_cheat_caller_address(launchpad.contract_address, ALICE()); - - launchpad.set_address_jediswap_factory_v2('jediswap'.try_into().unwrap()); - } - - #[test] - fn test_set_address_jediswap_factory_v2_ok() { - let (sender_address, _, launchpad) = request_fixture(); - let mut spy = spy_events(); - let jediswap_v2_addr: ContractAddress = 'jediswap'.try_into().unwrap(); - - start_cheat_caller_address(launchpad.contract_address, sender_address); - - launchpad.set_address_jediswap_factory_v2(jediswap_v2_addr); +// #[test] +// // #[fork("Mainnet")] +// #[should_panic(expected: ('no threshold raised',))] +// fn test_launch_liquidity_when_no_threshold_raised() { +// let (_, _, launchpad) = request_fixture(); - let expected_event = LaunchpadEvent::SetJediswapV2Factory( - SetJediswapV2Factory { address_jediswap_factory_v2: jediswap_v2_addr } - ); - spy.assert_emitted(@array![(launchpad.contract_address, expected_event)]); - } - - #[test] - #[should_panic(expected: ('Caller is missing role',))] - fn test_set_address_jediswap_nft_router_v2_non_admin() { - let (_, _, launchpad) = request_fixture(); - start_cheat_caller_address(launchpad.contract_address, ALICE()); - - launchpad.set_address_jediswap_nft_router_v2('jediswap'.try_into().unwrap()); - } - - #[test] - fn test_set_address_jediswap_nft_router_v2_ok() { - let (sender_address, _, launchpad) = request_fixture(); - let mut spy = spy_events(); - let jediswap_nft_v2_addr: ContractAddress = 'jediswap'.try_into().unwrap(); - - start_cheat_caller_address(launchpad.contract_address, sender_address); - - launchpad.set_address_jediswap_nft_router_v2(jediswap_nft_v2_addr); - - let expected_event = LaunchpadEvent::SetJediswapNFTRouterV2( - SetJediswapNFTRouterV2 { address_jediswap_nft_router_v2: jediswap_nft_v2_addr } - ); - spy.assert_emitted(@array![(launchpad.contract_address, expected_event)]); - } - - #[test] - #[should_panic(expected: ('Caller is missing role',))] - fn test_set_exchanges_address_non_admin() { - let (_, _, launchpad) = request_fixture(); - let jediswap_addr: ContractAddress = 'jediswap'.try_into().unwrap(); - start_cheat_caller_address(launchpad.contract_address, ALICE()); +// start_cheat_caller_address(launchpad.contract_address, OWNER()); - let exchange_addresses = array![(SupportedExchanges::Jediswap, jediswap_addr)].span(); - - launchpad.set_exchanges_address(exchange_addresses); - } +// let token_address = launchpad +// .create_and_launch_token( +// symbol: SYMBOL(), +// name: NAME(), +// initial_supply: DEFAULT_INITIAL_SUPPLY(), +// contract_address_salt: SALT(), +// is_unruggable: false +// ); - #[test] - fn test_set_exchanges_address_ok() { - let (sender_address, _, launchpad) = request_fixture(); - let jediswap_addr: ContractAddress = 'jediswap'.try_into().unwrap(); - start_cheat_caller_address(launchpad.contract_address, sender_address); - - let exchange_addresses = array![(SupportedExchanges::Jediswap, jediswap_addr)].span(); +// launchpad.launch_liquidity(token_address); +// } - launchpad.set_exchanges_address(exchange_addresses); - } - - #[test] - #[should_panic(expected: ('Caller is missing role',))] - fn test_set_class_hash_non_admin() { - let (_, _, launchpad) = request_fixture(); - start_cheat_caller_address(launchpad.contract_address, ALICE()); - - launchpad.set_class_hash(class_hash_const::<'hash'>()); - } - - #[test] - fn test_set_class_hash_ok() { - let (sender_address, _, launchpad) = request_fixture(); - start_cheat_caller_address(launchpad.contract_address, sender_address); - - launchpad.set_class_hash(class_hash_const::<'hash'>()); - } - - #[test] - #[should_panic(expected: ('coin not found',))] - fn test_sell_coin_for_invalid_coin() { - let (_, erc20, launchpad) = request_fixture(); - - launchpad.sell_coin(erc20.contract_address, 50_u256); - } - - - #[test] - // #[fork("Mainnet")] - fn launchpad_test_calculation() { - println!("launchpad_test_calculation"); - let (sender_address, erc20, launchpad) = request_fixture(); - start_cheat_caller_address_global(sender_address); - start_cheat_caller_address(erc20.contract_address, sender_address); - let default_token = launchpad.get_default_token(); - assert(default_token.token_address == erc20.contract_address, 'no default token'); - assert(default_token.starting_price == INITIAL_KEY_PRICE, 'no init price'); - start_cheat_caller_address(launchpad.contract_address, sender_address); - - let token_address = default_token.token_address; - let amount_to_buy = THRESHOLD_LIQUIDITY; - let amount_coin_get = run_calculation( - launchpad, amount_to_buy, token_address, sender_address, false, true - ); - println!("amount coin get {:?}", amount_coin_get); - - let amount_coin_sell = run_calculation( - launchpad, amount_to_buy, token_address, sender_address, true, true - ); - println!("amount_coin_sell {:?}", amount_coin_sell); - assert!(amount_coin_get == amount_coin_sell, "amount incorrect"); - } - - #[test] - fn test_get_coin_amount_by_quote_amount_for_buy_steps() { - let (sender_address, erc20, launchpad) = request_fixture(); +// #[test] +// fn test_get_threshold_liquidity() { +// let (_, _, launchpad) = request_fixture(); +// assert( +// THRESHOLD_LIQUIDITY == launchpad.get_threshold_liquidity(), 'wrong threshold liquidity' +// ); +// } + +// #[test] +// fn test_get_default_token() { +// let (_, erc20, launchpad) = request_fixture(); + +// let expected_token = TokenQuoteBuyCoin { +// token_address: erc20.contract_address, +// starting_price: INITIAL_KEY_PRICE, +// price: INITIAL_KEY_PRICE, +// is_enable: true, +// step_increase_linear: STEP_LINEAR_INCREASE, +// }; + +// assert(expected_token == launchpad.get_default_token(), 'wrong default token'); +// } + +// #[test] +// // #[fork("Mainnet")] +// fn test_get_coin_launch() { +// let (_, erc20, launchpad) = request_fixture(); + +// start_cheat_caller_address(launchpad.contract_address, OWNER()); + +// let token_address = launchpad +// .create_and_launch_token( +// symbol: SYMBOL(), +// name: NAME(), +// initial_supply: DEFAULT_INITIAL_SUPPLY(), +// contract_address_salt: SALT(), +// is_unruggable: false +// ); + +// let launched_token = launchpad.get_coin_launch(token_address); + +// assert(launched_token.owner == OWNER(), 'wrong owner'); +// assert(launched_token.token_address == token_address, 'wrong token address'); +// assert(launched_token.total_supply == DEFAULT_INITIAL_SUPPLY(), 'wrong initial supply'); +// assert( +// launched_token.bonding_curve_type.unwrap() == BondingType::Linear, +// 'wrong initial supply' +// ); +// assert(launched_token.price == 0_u256, 'wrong price'); +// assert(launched_token.liquidity_raised == 0_u256, 'wrong liquidation raised'); +// assert(launched_token.total_token_holded == 0_u256, 'wrong token holded'); +// assert( +// launched_token.token_quote.token_address == erc20.contract_address, 'wrong token quote' +// ); +// } + +// #[test] +// // #[fork("Mainnet")] +// fn test_get_share_key_of_user() { +// let (sender_address, erc20, launchpad) = request_fixture(); + +// let token_address = launchpad +// .create_and_launch_token( +// symbol: SYMBOL(), +// name: NAME(), +// initial_supply: DEFAULT_INITIAL_SUPPLY(), +// contract_address_salt: SALT(), +// is_unruggable: false +// ); +// let memecoin = IERC20Dispatcher { contract_address: token_address }; + +// let mut first_buy = 10_u256; +// run_buy_by_amount(launchpad, erc20, memecoin, first_buy, token_address, sender_address,); + +// let share_key = launchpad.get_share_key_of_user(sender_address, memecoin.contract_address); + +// assert(share_key.owner == sender_address, 'wrong owner'); +// assert(share_key.token_address == memecoin.contract_address, 'wrong token address'); +// } + +// #[test] +// // #[fork("Mainnet")] +// fn test_get_all_launch_tokens_and_coins() { +// let (sender_address, erc20, launchpad) = request_fixture(); +// let first_token: felt252 = 'token_1'; +// let second_token: felt252 = 'token_2'; +// let third_token: felt252 = 'token_3'; + +// let first_token_addr = launchpad +// .create_and_launch_token( +// symbol: 'FRST', +// name: first_token, +// initial_supply: DEFAULT_INITIAL_SUPPLY(), +// contract_address_salt: SALT(), +// is_unruggable: false +// ); + +// let second_token_addr = launchpad +// .create_and_launch_token( +// symbol: 'SCND', +// name: second_token, +// initial_supply: DEFAULT_INITIAL_SUPPLY(), +// contract_address_salt: SALT(), +// is_unruggable: false +// ); + +// let third_token_addr = launchpad +// .create_and_launch_token( +// symbol: 'THRD', +// name: third_token, +// initial_supply: DEFAULT_INITIAL_SUPPLY(), +// contract_address_salt: SALT(), +// is_unruggable: false +// ); + +// let all_launched_coins = launchpad.get_all_coins(); +// let all_launched_tokens = launchpad.get_all_launch(); + +// assert(all_launched_coins.len() == 3, 'wrong number of coins'); +// assert(all_launched_tokens.len() == 3, 'wrong number of tokens'); +// assert(*all_launched_coins.at(0).name == first_token, 'wrong coin name'); +// assert(*all_launched_coins.at(1).name == second_token, 'wrong coin name'); +// assert(*all_launched_coins.at(2).name == third_token, 'wrong coin name'); +// assert(*all_launched_tokens.at(0).token_address == first_token_addr, 'wrong token address'); +// assert( +// *all_launched_tokens.at(1).token_address == second_token_addr, 'wrong token address' +// ); +// assert(*all_launched_tokens.at(2).token_address == third_token_addr, 'wrong token address'); +// } - start_cheat_caller_address(launchpad.contract_address, sender_address); - let token_address = launchpad - .create_and_launch_token( - symbol: SYMBOL(), - name: NAME(), - initial_supply: DEFAULT_INITIAL_SUPPLY(), - contract_address_salt: SALT(), - is_unruggable: false, - ); +// #[test] +// #[should_panic(expected: ('share too low',))] +// fn test_sell_coin_when_share_too_low() { +// let (sender_address, erc20, launchpad) = request_fixture(); - let memecoin = IERC20Dispatcher { contract_address: token_address }; - - let mut quote_amount: u256 = 1; // Example amount of quote token for buying - - // TODO calculation of amount received - let expected_meme_amount_max: u256 = DEFAULT_INITIAL_SUPPLY() - / LIQUIDITY_RATIO; // Replace with the expected value from the formula +// start_cheat_caller_address(launchpad.contract_address, OWNER()); - let expected_meme_amount: u256 = expected_meme_amount_max - / 10_u256; // Replace with the expected value from the formula +// let token_address = launchpad +// .create_and_launch_token( +// symbol: SYMBOL(), +// name: NAME(), +// initial_supply: DEFAULT_INITIAL_SUPPLY(), +// contract_address_salt: SALT(), +// is_unruggable: false +// ); - let result = launchpad.get_coin_amount_by_quote_amount(token_address, quote_amount, false,); +// let memecoin = IERC20Dispatcher { contract_address: token_address }; - println!("result {:?}", result); - println!("expected_meme_amount {:?}", expected_meme_amount); +// run_sell_by_amount( +// launchpad, erc20, memecoin, THRESHOLD_LIQUIDITY, token_address, sender_address, +// ); +// } - run_buy_by_amount(launchpad, erc20, memecoin, quote_amount, token_address, sender_address,); - let quote_amount_2: u256 = 1; // Example amount of quote token for buying - assert(result == expected_meme_amount, 'Error: Buy calculation mismatch'); +// #[test] +// #[should_panic(expected: ('liquidity <= amount',))] +// fn test_sell_coin_when_quote_amount_is_greater_than_liquidity_raised() { +// let (sender_address, erc20, launchpad) = request_fixture(); - println!("result {:?}", result); - println!("expected_meme_amount {:?}", expected_meme_amount); +// start_cheat_caller_address(launchpad.contract_address, sender_address); - let share_key = launchpad.get_share_key_of_user(sender_address, memecoin.contract_address); +// let token_address = launchpad +// .create_and_launch_token( +// symbol: SYMBOL(), +// name: NAME(), +// initial_supply: DEFAULT_INITIAL_SUPPLY(), +// contract_address_salt: SALT(), +// is_unruggable: false +// ); - assert(share_key.owner == sender_address, 'wrong owner'); - assert(share_key.amount_owned == result, 'wrong result'); - assert(share_key.amount_owned == expected_meme_amount, 'wrong expected'); +// let memecoin = IERC20Dispatcher { contract_address: token_address }; - let result = launchpad - .get_coin_amount_by_quote_amount(token_address, quote_amount_2, false,); - } - // #[test] -// // #[fork("Mainnet")] -// fn test_launch_liquidity_ok() { -// let (sender_address, erc20, launchpad) = request_fixture(); - - // start_cheat_caller_address(launchpad.contract_address, OWNER()); - - // let token_address = launchpad -// .create_and_launch_token( -// symbol: SYMBOL(), -// name: NAME(), -// initial_supply: DEFAULT_INITIAL_SUPPLY(), -// contract_address_salt: SALT(), -// is_unruggable: false +// run_buy_by_amount(launchpad, erc20, memecoin, 10_u256, token_address, sender_address,); + +// run_sell_by_amount(launchpad, erc20, memecoin, 20_u256, token_address, sender_address,); +// } + +// #[test] +// #[fork("Mainnet")] +// fn test_launchpad_end_to_end() { +// let (sender_address, erc20, launchpad) = request_fixture(); +// let starting_price = THRESHOLD_LIQUIDITY / DEFAULT_INITIAL_SUPPLY(); +// let slope = calculate_slope(DEFAULT_INITIAL_SUPPLY()); +// let mut spy = spy_events(); +// // let mut spy = spy_events(SpyOn::One(launchpad.contract_address)); + +// // start_cheat_caller_address_global(sender_address); +// start_cheat_caller_address(erc20.contract_address, sender_address); + +// let default_token = launchpad.get_default_token(); + +// assert(default_token.token_address == erc20.contract_address, 'no default token'); +// assert(default_token.starting_price == INITIAL_KEY_PRICE, 'no init price'); +// assert( +// default_token.step_increase_linear == STEP_LINEAR_INCREASE, 'no step_increase_linear' // ); +// assert(default_token.is_enable == true, 'not enabled'); - // let memecoin = IERC20Dispatcher { contract_address: token_address }; +// start_cheat_caller_address(launchpad.contract_address, sender_address); - // run_buy_by_amount( -// launchpad, erc20, memecoin, THRESHOLD_LIQUIDITY, token_address, sender_address, -// ); +// let token_address = launchpad +// .create_and_launch_token( +// symbol: SYMBOL(), +// name: NAME(), +// initial_supply: DEFAULT_INITIAL_SUPPLY(), +// contract_address_salt: SALT(), +// is_unruggable: false +// ); - // launchpad.launch_liquidity(token_address); -// } +// let memecoin = IERC20Dispatcher { contract_address: token_address }; +// let amount_first_buy = 10_u256; - // #[test] -// #[fork("Mainnet")] -// fn launchpad_buy_all_few_steps() { -// println!("launchpad_buy_all_few_steps"); -// let (sender_address, erc20, launchpad) = request_fixture(); -// start_cheat_caller_address_global(sender_address); -// start_cheat_caller_address(erc20.contract_address, sender_address); -// // Call a view function of the contract -// // Check default token used -// let default_token = launchpad.get_default_token(); -// assert(default_token.token_address == erc20.contract_address, 'no default token'); -// assert(default_token.starting_price == INITIAL_KEY_PRICE, 'no init price'); -// start_cheat_caller_address(launchpad.contract_address, sender_address); -// println!("create and launch token"); -// let token_address = launchpad -// .create_and_launch_token( -// // owner: OWNER(), -// symbol: SYMBOL(), -// name: NAME(), -// initial_supply: DEFAULT_INITIAL_SUPPLY(), -// contract_address_salt: SALT(), +// run_buy_by_amount( +// launchpad, erc20, memecoin, amount_first_buy, token_address, sender_address, // ); -// println!("test token_address {:?}", token_address); -// let memecoin = IERC20Dispatcher { contract_address: token_address }; - // // All buy -// let mut first_buy = 10_u256; +// run_sell_by_amount( +// launchpad, erc20, memecoin, amount_first_buy, token_address, sender_address, +// ); - // run_buy_by_amount(launchpad, erc20, memecoin, first_buy, token_address, sender_address,); +// run_buy_by_amount( +// launchpad, erc20, memecoin, THRESHOLD_LIQUIDITY, token_address, sender_address, +// ); - // // run_buy_by_amount(launchpad, erc20, memecoin, first_buy, token_address, -// sender_address,); +// run_sell_by_amount( +// launchpad, erc20, memecoin, THRESHOLD_LIQUIDITY, token_address, sender_address, +// ); - // run_buy_by_amount( -// launchpad, -// erc20, -// memecoin, -// THRESHOLD_LIQUIDITY - first_buy, -// token_address, -// sender_address, -// ); -// } -// #[test] -// #[fork("Mainnet")] -// fn launchpad_buy_and_sell() { -// println!("launchpad_buy_and_sell"); -// let (sender_address, erc20, launchpad) = request_fixture(); -// // let amount_key_buy = 1_u256; -// start_cheat_caller_address_global(sender_address); -// start_cheat_caller_address(erc20.contract_address, sender_address); -// // Call a view function of the contract -// // Check default token used -// let default_token = launchpad.get_default_token(); -// assert(default_token.token_address == erc20.contract_address, 'no default token'); -// assert(default_token.starting_price == INITIAL_KEY_PRICE, 'no init price'); - - // start_cheat_caller_address(launchpad.contract_address, sender_address); - - // println!("create and launch token"); -// let token_address = launchpad -// .create_and_launch_token( -// // owner: OWNER(), -// symbol: SYMBOL(), -// name: NAME(), -// initial_supply: DEFAULT_INITIAL_SUPPLY(), -// contract_address_salt: SALT(), +// let expected_create_token_event = LaunchpadEvent::CreateToken( +// CreateToken { +// caller: sender_address, +// token_address: token_address, +// symbol: SYMBOL(), +// name: NAME(), +// initial_supply: DEFAULT_INITIAL_SUPPLY(), +// total_supply: DEFAULT_INITIAL_SUPPLY(), +// is_unruggable: false, +// } +// ); + +// let expected_launch_token_event = LaunchpadEvent::CreateLaunch( +// CreateLaunch { +// caller: OWNER(), +// token_address: token_address, +// amount: 0, +// price: starting_price, +// total_supply: DEFAULT_INITIAL_SUPPLY(), +// slope: slope, +// threshold_liquidity: THRESHOLD_LIQUIDITY, +// quote_token_address: erc20.contract_address, +// is_unruggable: true +// } // ); -// println!("test token_address {:?}", token_address); - - // let memecoin = IERC20Dispatcher { contract_address: token_address }; -// let amount_first_buy = 10_u256; - - // // // First buy with 10 quote token -// run_buy_by_amount( -// launchpad, erc20, memecoin, amount_first_buy, token_address, sender_address, -// ); -// // let mut total_amount_buy = amount_first_buy; - - // let new_amount = THRESHOLD_LIQUIDITY - amount_first_buy; -// // // First sell with 10 quote token -// run_sell_by_amount( -// launchpad, erc20, memecoin, amount_first_buy, token_address, sender_address, -// ); -// // // Threshold buy - 1 -// // run_buy_by_amount( -// // launchpad, erc20, memecoin, new_amount, token_address, sender_address, -// // ); - - // } - - // #[test] -// #[fork("Mainnet")] -// #[should_panic(expected: ('threshold liquidity exceeded',))] -// fn launchpad_buy_more_then_liquidity_threshold() { -// println!("launchpad_buy_more_then_liquidity_threshold"); -// let (sender_address, erc20, launchpad) = request_fixture(); -// start_cheat_caller_address_global(sender_address); -// start_cheat_caller_address(erc20.contract_address, sender_address); -// let default_token = launchpad.get_default_token(); -// assert(default_token.token_address == erc20.contract_address, 'no default token'); -// assert(default_token.starting_price == INITIAL_KEY_PRICE, 'no init price'); -// start_cheat_caller_address(launchpad.contract_address, sender_address); - - // let token_address = launchpad -// .create_token( -// recipient: OWNER(), -// // owner: OWNER(), -// symbol: SYMBOL(), -// name: NAME(), -// initial_supply: DEFAULT_INITIAL_SUPPLY(), -// contract_address_salt: SALT(), + +// spy +// .assert_emitted( +// @array![ +// (launchpad.contract_address, expected_create_token_event), +// (launchpad.contract_address, expected_launch_token_event) +// ] +// ); +// } + + +// #[test] +// #[fork("Mainnet")] +// fn test_add_liquidity_ekubo() { +// let (sender, erc20, launchpad) = request_fixture(); +// start_cheat_caller_address(launchpad.contract_address, OWNER()); +// let token_address = launchpad +// .create_and_launch_token( +// symbol: SYMBOL(), +// name: NAME(), +// initial_supply: DEFAULT_INITIAL_SUPPLY(), +// contract_address_salt: SALT(), +// is_unruggable: false +// ); +// println!("token_address ekubo launch: {:?}", token_address); +// println!( +// "Balance of launchpad: {:?}", +// IERC20Dispatcher { contract_address: token_address } +// .balance_of(launchpad.contract_address) // ); -// // println!("test token_address {:?}", token_address); -// let memecoin = IERC20Dispatcher { contract_address: token_address }; -// start_cheat_caller_address(memecoin.contract_address, sender_address); - - // let balance_contract = memecoin.balance_of(launchpad.contract_address); -// println!("test balance_contract {:?}", balance_contract); - - // let total_supply = memecoin.total_supply(); -// println!(" memecoin total_supply {:?}", total_supply); -// memecoin.approve(launchpad.contract_address, total_supply); - - // let allowance = memecoin.allowance(sender_address, launchpad.contract_address); -// println!("test allowance meme coin{}", allowance); -// // memecoin.transfer(launchpad.contract_address, total_supply); -// stop_cheat_caller_address(memecoin.contract_address); - - // start_cheat_caller_address(launchpad.contract_address, sender_address); - - // launchpad.launch_token(token_address); -// let amount_first_buy = 9_u256; - - // run_buy_by_amount( -// launchpad, erc20, memecoin, amount_first_buy, token_address, sender_address, -// ); -// // let mut total_amount_buy = amount_first_buy; - - // let mut amount_second = 2_u256; -// run_buy_by_amount( -// launchpad, erc20, memecoin, amount_second, token_address, sender_address, -// ); -// // // // First buy with 10 quote token -// // let res = run_sell_by_amount( -// // launchpad, erc20, memecoin, amount_first_buy, token_address, sender_address, -// // ); - - // // // Final buy -// // let res = run_buy_by_amount( -// // launchpad, -// // erc20, -// // memecoin, -// // THRESHOLD_LIQUIDITY - total_amount_buy, -// // token_address, -// // sender_address, -// // ); -// } +// let launch = launchpad.get_coin_launch(token_address); +// let starting_price = i129 { sign: true, mag: 100_u128 }; +// println!("Initial available: {:?}", launch.initial_available_supply); +// let lp_meme_supply = launch.initial_available_supply - launch.available_supply; +// println!("lp_meme_supply {:?}", lp_meme_supply); +// let memecoin = IERC20Dispatcher { contract_address: token_address }; +// start_cheat_caller_address(memecoin.contract_address, OWNER()); +// // memecoin.transfer(launchpad.contract_address, DEFAULT_INITIAL_SUPPLY()); +// memecoin.transfer(launchpad.contract_address, lp_meme_supply); +// memecoin.approve(launchpad.contract_address, lp_meme_supply); +// memecoin.approve(EKUBO_EXCHANGE_ADDRESS(), lp_meme_supply); +// stop_cheat_caller_address(memecoin.contract_address); + +// let params: EkuboLaunchParameters = EkuboLaunchParameters { +// owner: launch.owner, +// token_address: launch.token_address, +// quote_address: launch.token_quote.token_address, +// lp_supply: lp_meme_supply, +// // lp_supply: launch.liquidity_raised, +// pool_params: EkuboPoolParameters { +// fee: 0xc49ba5e353f7d00000000000000000, +// tick_spacing: 5982, +// starting_price, +// bound: 88719042, +// } +// }; +// // start_cheat_caller_address(erc20.contract_address, OWNER()); + +// // memecoin.transfer(FACTORY_ADDRESS(), DEFAULT_INITIAL_SUPPLY()); +// let quote_token = IERC20Dispatcher { contract_address: erc20.contract_address }; +// // erc20.transfer(launchpad.contract_address, launch.liquidity_raised); +// start_cheat_caller_address(launchpad.contract_address, OWNER()); +// println!("buy threshold liquidity"); + +// run_buy_by_amount( +// launchpad, quote_token, memecoin, THRESHOLD_LIQUIDITY, token_address, OWNER(), +// ); +// let balance_quote_launch = quote_token.balance_of(launchpad.contract_address); +// println!("balance quote {:?}", balance_quote_launch); + +// println!("add liquidity ekubo"); +// // launchpad.add_liquidity_ekubo(token_address, params); +// start_cheat_caller_address(launchpad.contract_address, OWNER()); + +// launchpad.add_liquidity_ekubo(token_address); +// stop_cheat_caller_address(launchpad.contract_address); +// } + + +// #[test] +// #[fork("Mainnet")] +// fn test_add_liquidity_jediswap() { +// println!("try add liq jediswap"); +// let (sender, erc20, launchpad) = request_fixture(); +// start_cheat_caller_address(launchpad.contract_address, OWNER()); +// let token_address = launchpad +// .create_and_launch_token( +// symbol: SYMBOL(), +// name: NAME(), +// initial_supply: DEFAULT_INITIAL_SUPPLY(), +// contract_address_salt: SALT(), +// is_unruggable: false +// ); +// println!("token_address ekubo launch: {:?}", token_address); +// println!( +// "Balance of launchpad: {:?}", +// IERC20Dispatcher { contract_address: token_address } +// .balance_of(launchpad.contract_address) +// ); +// let launch = launchpad.get_coin_launch(token_address); +// let starting_price = i129 { sign: true, mag: 100_u128 }; +// println!("Initial available: {:?}", launch.initial_available_supply); +// let lp_meme_supply = launch.initial_available_supply - launch.available_supply; +// println!("lp_meme_supply {:?}", lp_meme_supply); +// let memecoin = IERC20Dispatcher { contract_address: token_address }; +// start_cheat_caller_address(memecoin.contract_address, OWNER()); +// // memecoin.transfer(launchpad.contract_address, DEFAULT_INITIAL_SUPPLY()); +// memecoin.transfer(launchpad.contract_address, lp_meme_supply); +// memecoin.approve(launchpad.contract_address, lp_meme_supply); +// memecoin.approve(EKUBO_EXCHANGE_ADDRESS(), lp_meme_supply); +// stop_cheat_caller_address(memecoin.contract_address); + +// let quote_token = IERC20Dispatcher { contract_address: erc20.contract_address }; +// start_cheat_caller_address(launchpad.contract_address, OWNER()); +// println!("buy threshold liquidity"); + +// run_buy_by_amount( +// launchpad, quote_token, memecoin, THRESHOLD_LIQUIDITY, token_address, OWNER(), +// ); +// let balance_quote_launch = quote_token.balance_of(launchpad.contract_address); +// println!("balance quote {:?}", balance_quote_launch); + +// println!("add liquidity ekubo"); +// // launchpad.add_liquidity_ekubo(token_address, params); +// // launchpad.add_liquidity_ekubo(token_address); +// launchpad.add_liquidity_jediswap(token_address); + +// stop_cheat_caller_address(launchpad.contract_address); +// } + +// #[test] +// #[fork("Mainnet")] +// fn test_create_and_add_liquidity_unrug() { +// let (b, quote_token, launchpad) = request_fixture(); +// let starting_price = i129 { sign: true, mag: 4600158 }; // 0.01ETH/MEME +// let quote_to_deposit = 215_000; +// let factory = IFactoryDispatcher { contract_address: FACTORY_ADDRESS() }; + +// let total_supply = DEFAULT_INITIAL_SUPPLY(); +// // start_cheat_caller_address(launchpad.contract_address, OWNER()); +// let token_address = launchpad +// .create_unrug_token( +// owner: launchpad.contract_address, +// name: NAME(), +// symbol: SYMBOL(), +// initial_supply: DEFAULT_INITIAL_SUPPLY(), +// contract_address_salt: SALT() + 1, +// is_launch_bonding_now: true +// ); +// println!("token_address unrug: {:?}", token_address); + +// start_cheat_caller_address(token_address, launchpad.contract_address); + +// let memecoin = IERC20Dispatcher { contract_address: token_address }; +// let mut balance_meme_launch = memecoin.balance_of(launchpad.contract_address); +// println!("balance meme {:?}", balance_meme_launch); + +// let mut balance_meme_launch_owner = memecoin.balance_of(OWNER()); +// println!("balance meme owner {:?}", balance_meme_launch_owner); + +// let mut balance_meme_launch_factory = memecoin.balance_of(FACTORY_ADDRESS()); +// println!("balance factory {:?}", balance_meme_launch_factory); + +// // memecoin.transfer(launchpad.contract_address, DEFAULT_INITIAL_SUPPLY()); +// balance_meme_launch = memecoin.balance_of(launchpad.contract_address); +// println!("balance meme {:?}", balance_meme_launch); +// start_cheat_caller_address(memecoin.contract_address, OWNER()); +// // memecoin.approve(launchpad.contract_address, total_supply); +// // memecoin.transfer(launchpad.contract_address, total_supply); + +// // stop_cheat_caller_address(token_address); +// let launch = launchpad.get_coin_launch(token_address); + +// // let total_token_holded: u256 = 1_000 * pow_256(10, 18); +// let total_token_holded: u256 = launch.total_supply - launch.total_token_holded; +// // let total_token_holded: u256 = 1_000; + +// let launch_params = LaunchParameters { +// memecoin_address: token_address, +// transfer_restriction_delay: 100, +// max_percentage_buy_launch: 200, // 2% +// quote_address: quote_token.contract_address, +// initial_holders: array![].span(), +// initial_holders_amounts: array![].span(), +// // initial_holders: array![launchpad.contract_address].span(), +// // initial_holders_amounts: array![total_token_holded].span(), +// }; + +// let ekubo_pool_params = EkuboPoolParameters { +// fee: 0xc49ba5e353f7d00000000000000000, +// tick_spacing: 5982, +// starting_price, +// bound: 88719042 +// }; +// start_cheat_caller_address(launchpad.contract_address, OWNER()); +// println!("buy liquidity threshold unrug"); + +// run_buy_by_amount( +// launchpad, quote_token, memecoin, THRESHOLD_LIQUIDITY, token_address, OWNER(), +// ); +// let balance_quote_launch = quote_token.balance_of(launchpad.contract_address); +// println!("balance balance_quote_launch {:?}", balance_quote_launch); +// println!("add liquidity unrug"); +// let (id, position) = launchpad +// .add_liquidity_unrug( +// token_address, +// launch_params, +// EkuboPoolParameters { +// fee: 0xc49ba5e353f7d00000000000000000, +// tick_spacing: 5982, +// starting_price, +// bound: 88719042 +// } +// ); +// // println!("id: {:?}", id); + +// // let pool_key = PoolKey { +// // token0: position.pool_key.token0, +// // token1: position.pool_key.token1, +// // fee: position.pool_key.fee.try_into().unwrap(), +// // tick_spacing: position.pool_key.tick_spacing.try_into().unwrap(), +// // extension: position.pool_key.extension +// // }; + +// // let core = ICoreDispatcher { contract_address: EKUBO_CORE() }; +// // let liquidity = core.get_pool_liquidity(pool_key); +// // let price = core.get_pool_price(pool_key); +// // let reserve_memecoin = IERC20Dispatcher { contract_address: token_address } +// // .balance_of(core.contract_address); +// // let reserve_quote = IERC20Dispatcher { contract_address: quote_token.contract_address } +// // .balance_of(core.contract_address); +// // println!("Liquidity: {}", liquidity); + +// } + + +// #[test] +// #[fork("Mainnet")] +// fn test_create_and_add_liquidity_unrug_liq_without_launchpad_threshold() { +// let (b, quote_token, launchpad) = request_fixture(); +// let starting_price = i129 { sign: true, mag: 4600158 }; // 0.01ETH/MEME +// let quote_to_deposit = 215_000; +// let factory = IFactoryDispatcher { contract_address: FACTORY_ADDRESS() }; + +// let total_supply = DEFAULT_INITIAL_SUPPLY(); +// // start_cheat_caller_address(launchpad.contract_address, OWNER()); +// let token_address = launchpad +// .create_unrug_token( +// owner: launchpad.contract_address, +// name: NAME(), +// symbol: SYMBOL(), +// initial_supply: DEFAULT_INITIAL_SUPPLY(), +// contract_address_salt: SALT() + 1, +// is_launch_bonding_now: false +// ); +// println!("token_address unrug: {:?}", token_address); + +// start_cheat_caller_address(token_address, launchpad.contract_address); + +// let memecoin = IERC20Dispatcher { contract_address: token_address }; +// let mut balance_meme_launch = memecoin.balance_of(launchpad.contract_address); +// println!("balance meme {:?}", balance_meme_launch); + +// let mut balance_meme_launch_owner = memecoin.balance_of(OWNER()); +// println!("balance meme owner {:?}", balance_meme_launch_owner); + +// let mut balance_meme_launch_factory = memecoin.balance_of(FACTORY_ADDRESS()); +// println!("balance factory {:?}", balance_meme_launch_factory); + +// // memecoin.transfer(launchpad.contract_address, DEFAULT_INITIAL_SUPPLY()); +// balance_meme_launch = memecoin.balance_of(launchpad.contract_address); +// println!("balance meme {:?}", balance_meme_launch); +// start_cheat_caller_address(memecoin.contract_address, OWNER()); +// // memecoin.approve(launchpad.contract_address, total_supply); +// // memecoin.transfer(launchpad.contract_address, total_supply); + +// // stop_cheat_caller_address(token_address); +// let launch = launchpad.get_coin_launch(token_address); +// let lp_meme_supply = launch.initial_available_supply - launch.available_supply; + +// // let total_token_holded: u256 = 1_000 * pow_256(10, 18); +// let total_token_holded: u256 = launch.total_supply - launch.total_token_holded; +// // let total_token_holded: u256 = 1_000; + +// let launch_params = LaunchParameters { +// memecoin_address: token_address, +// transfer_restriction_delay: 100, +// max_percentage_buy_launch: 200, // 2% +// quote_address: quote_token.contract_address, +// initial_holders: array![].span(), +// initial_holders_amounts: array![].span(), +// // initial_holders: array![launchpad.contract_address].span(), +// // initial_holders_amounts: array![total_token_holded].span(), +// }; + +// let ekubo_pool_params = EkuboPoolParameters { +// fee: 0xc49ba5e353f7d00000000000000000, +// tick_spacing: 5982, +// starting_price, +// bound: 88719042 +// }; +// start_cheat_caller_address(launchpad.contract_address, OWNER()); +// println!("buy liquidity threshold unrug"); + +// let erc20 = IERC20Dispatcher { contract_address: quote_token.contract_address }; + +// erc20.transfer(launchpad.contract_address, quote_to_deposit); +// // run_buy_by_amount( +// // launchpad, quote_token, memecoin, THRESHOLD_LIQUIDITY, token_address, OWNER(), +// // ); +// let balance_quote_launch = quote_token.balance_of(launchpad.contract_address); +// println!("balance balance_quote_launch {:?}", balance_quote_launch); +// println!("add liquidity unrug"); +// let (id, position) = launchpad +// .add_liquidity_unrug_lp( +// token_address, +// quote_token.contract_address, +// lp_meme_supply, +// launch_params, +// EkuboPoolParameters { +// fee: 0xc49ba5e353f7d00000000000000000, +// tick_spacing: 5982, +// starting_price, +// bound: 88719042 +// } +// ); +// // println!("id: {:?}", id); + +// // let pool_key = PoolKey { +// // token0: position.pool_key.token0, +// // token1: position.pool_key.token1, +// // fee: position.pool_key.fee.try_into().unwrap(), +// // tick_spacing: position.pool_key.tick_spacing.try_into().unwrap(), +// // extension: position.pool_key.extension +// // }; + +// // let core = ICoreDispatcher { contract_address: EKUBO_CORE() }; +// // let liquidity = core.get_pool_liquidity(pool_key); +// // let price = core.get_pool_price(pool_key); +// // let reserve_memecoin = IERC20Dispatcher { contract_address: token_address } +// // .balance_of(core.contract_address); +// // let reserve_quote = IERC20Dispatcher { contract_address: quote_token.contract_address } +// // .balance_of(core.contract_address); +// // println!("Liquidity: {}", liquidity); + +// } + + +// #[test] +// #[fork("Mainnet")] +// fn test_create_and_add_liquidity_unrug_liq_without_launchpad_but_launch() { +// let (b, quote_token, launchpad) = request_fixture(); +// let starting_price = i129 { sign: true, mag: 4600158 }; // 0.01ETH/MEME +// let quote_to_deposit = 215_000; +// let factory = IFactoryDispatcher { contract_address: FACTORY_ADDRESS() }; + +// let total_supply = DEFAULT_INITIAL_SUPPLY(); +// // start_cheat_caller_address(launchpad.contract_address, OWNER()); +// let token_address = launchpad +// .create_unrug_token( +// owner: launchpad.contract_address, +// name: NAME(), +// symbol: SYMBOL(), +// initial_supply: DEFAULT_INITIAL_SUPPLY(), +// contract_address_salt: SALT() + 1, +// is_launch_bonding_now: true +// ); +// println!("token_address unrug: {:?}", token_address); + +// start_cheat_caller_address(token_address, launchpad.contract_address); + +// let memecoin = IERC20Dispatcher { contract_address: token_address }; +// let mut balance_meme_launch = memecoin.balance_of(launchpad.contract_address); +// println!("balance meme {:?}", balance_meme_launch); + +// let mut balance_meme_launch_owner = memecoin.balance_of(OWNER()); +// println!("balance meme owner {:?}", balance_meme_launch_owner); + +// let mut balance_meme_launch_factory = memecoin.balance_of(FACTORY_ADDRESS()); +// println!("balance factory {:?}", balance_meme_launch_factory); + +// // memecoin.transfer(launchpad.contract_address, DEFAULT_INITIAL_SUPPLY()); +// balance_meme_launch = memecoin.balance_of(launchpad.contract_address); +// println!("balance meme {:?}", balance_meme_launch); +// start_cheat_caller_address(memecoin.contract_address, OWNER()); +// // memecoin.approve(launchpad.contract_address, total_supply); +// // memecoin.transfer(launchpad.contract_address, total_supply); + +// // stop_cheat_caller_address(token_address); +// let launch = launchpad.get_coin_launch(token_address); + +// let lp_meme_supply = DEFAULT_INITIAL_SUPPLY() / 5; + +// // let total_token_holded: u256 = 1_000 * pow_256(10, 18); +// // let total_token_holded: u256 = launch.total_supply - launch.total_token_holded; +// let total_token_holded: u256 = lp_meme_supply / 10; +// // let total_token_holded: u256 = 1_000; + +// let launch_params = LaunchParameters { +// memecoin_address: token_address, +// transfer_restriction_delay: 100, +// max_percentage_buy_launch: 200, // 2% +// quote_address: quote_token.contract_address, +// initial_holders: array![].span(), +// initial_holders_amounts: array![].span(), +// // initial_holders: array![launchpad.contract_address].span(), +// // initial_holders_amounts: array![total_token_holded].span(), +// }; + +// let ekubo_pool_params = EkuboPoolParameters { +// fee: 0xc49ba5e353f7d00000000000000000, +// tick_spacing: 5982, +// starting_price, +// bound: 88719042 +// }; +// start_cheat_caller_address(launchpad.contract_address, OWNER()); +// println!("buy liquidity threshold unrug"); + +// run_buy_by_amount( +// launchpad, quote_token, memecoin, THRESHOLD_LIQUIDITY, token_address, OWNER(), +// ); +// let balance_quote_launch = quote_token.balance_of(launchpad.contract_address); +// println!("balance balance_quote_launch {:?}", balance_quote_launch); +// println!("add liquidity unrug"); +// let (id, position) = launchpad +// .add_liquidity_unrug_lp( +// token_address, +// quote_token.contract_address, +// lp_meme_supply, +// launch_params, +// EkuboPoolParameters { +// fee: 0xc49ba5e353f7d00000000000000000, +// tick_spacing: 5982, +// starting_price, +// bound: 88719042 +// } +// ); +// // println!("id: {:?}", id); + +// // let pool_key = PoolKey { +// // token0: position.pool_key.token0, +// // token1: position.pool_key.token1, +// // fee: position.pool_key.fee.try_into().unwrap(), +// // tick_spacing: position.pool_key.tick_spacing.try_into().unwrap(), +// // extension: position.pool_key.extension +// // }; + +// // let core = ICoreDispatcher { contract_address: EKUBO_CORE() }; +// // let liquidity = core.get_pool_liquidity(pool_key); +// // let price = core.get_pool_price(pool_key); +// // let reserve_memecoin = IERC20Dispatcher { contract_address: token_address } +// // .balance_of(core.contract_address); +// // let reserve_quote = IERC20Dispatcher { contract_address: quote_token.contract_address } +// // .balance_of(core.contract_address); +// // println!("Liquidity: {}", liquidity); + +// } + + +// #[test] +// #[should_panic(expected: ('Caller is missing role',))] +// fn test_set_token_with_non_admin() { +// let (_, erc20, launchpad) = request_fixture(); + +// let expected_token = TokenQuoteBuyCoin { +// token_address: erc20.contract_address, +// starting_price: INITIAL_KEY_PRICE, +// price: INITIAL_KEY_PRICE, +// is_enable: true, +// step_increase_linear: STEP_LINEAR_INCREASE, +// }; + +// start_cheat_caller_address(launchpad.contract_address, ALICE()); +// launchpad.set_token(expected_token); +// } + +// #[test] +// #[should_panic(expected: ('protocol_fee_too_high',))] +// fn test_set_protocol_fee_percent_too_high() { +// let (_, _, launchpad) = request_fixture(); + +// launchpad.set_protocol_fee_percent(MAX_FEE_PROTOCOL + 1); +// } + +// #[test] +// #[should_panic(expected: ('protocol_fee_too_low',))] +// fn test_set_protocol_fee_percent_too_low() { +// let (_, _, launchpad) = request_fixture(); + +// launchpad.set_protocol_fee_percent(MIN_FEE_PROTOCOL - 1); +// } + +// #[test] +// #[should_panic(expected: ('Caller is missing role',))] +// fn test_set_protocol_fee_percent_non_admin() { +// let (_, _, launchpad) = request_fixture(); + +// launchpad.set_protocol_fee_percent(MID_FEE_PROTOCOL); +// } + +// #[test] +// fn test_set_protocol_fee_ok() { +// let (sender_address, _, launchpad) = request_fixture(); +// start_cheat_caller_address(launchpad.contract_address, sender_address); + +// launchpad.set_protocol_fee_percent(MID_FEE_PROTOCOL); +// } + +// #[test] +// #[should_panic(expected: ('creator_fee_too_low',))] +// fn test_set_creator_fee_percent_too_low() { +// let (sender_address, _, launchpad) = request_fixture(); +// start_cheat_caller_address(launchpad.contract_address, sender_address); + +// launchpad.set_creator_fee_percent(MIN_FEE_CREATOR - 1); +// } + +// #[test] +// #[should_panic(expected: ('creator_fee_too_high',))] +// fn test_set_creator_fee_percent_too_high() { +// let (sender_address, _, launchpad) = request_fixture(); +// start_cheat_caller_address(launchpad.contract_address, sender_address); + +// launchpad.set_creator_fee_percent(MAX_FEE_CREATOR + 1); +// } + +// #[test] +// #[should_panic(expected: ('Caller is missing role',))] +// fn test_set_creator_fee_percent_non_admin() { +// let (_, _, launchpad) = request_fixture(); +// start_cheat_caller_address(launchpad.contract_address, ALICE()); + +// launchpad.set_creator_fee_percent(MID_FEE_PROTOCOL); +// } + +// #[test] +// fn test_set_creator_fee_percent_ok() { +// let (sender_address, _, launchpad) = request_fixture(); +// start_cheat_caller_address(launchpad.contract_address, sender_address); + +// launchpad.set_creator_fee_percent(MID_FEE_CREATOR); +// } + +// #[test] +// #[should_panic(expected: ('Caller is missing role',))] +// fn test_set_dollar_paid_coin_creation_non_admin() { +// let (_, _, launchpad) = request_fixture(); +// start_cheat_caller_address(launchpad.contract_address, ALICE()); + +// launchpad.set_dollar_paid_coin_creation(50_u256); +// } + +// #[test] +// fn test_set_dollar_paid_coin_creation_ok() { +// let (sender_address, _, launchpad) = request_fixture(); +// start_cheat_caller_address(launchpad.contract_address, sender_address); + +// launchpad.set_dollar_paid_coin_creation(50_u256); +// } + + +// #[test] +// #[should_panic(expected: ('Caller is missing role',))] +// fn test_set_dollar_paid_launch_creation_non_admin() { +// let (_, _, launchpad) = request_fixture(); +// start_cheat_caller_address(launchpad.contract_address, ALICE()); + +// launchpad.set_dollar_paid_launch_creation(50_u256); +// } + +// #[test] +// fn test_set_dollar_paid_launch_creation_ok() { +// let (sender_address, _, launchpad) = request_fixture(); +// start_cheat_caller_address(launchpad.contract_address, sender_address); + +// launchpad.set_dollar_paid_launch_creation(50_u256); +// } + + +// #[test] +// #[should_panic(expected: ('Caller is missing role',))] +// fn test_set_dollar_paid_finish_percentage_non_admin() { +// let (_, _, launchpad) = request_fixture(); +// start_cheat_caller_address(launchpad.contract_address, ALICE()); + +// launchpad.set_dollar_paid_finish_percentage(50_u256); +// } + +// #[test] +// fn test_set_dollar_paid_finish_percentage_ok() { +// let (sender_address, _, launchpad) = request_fixture(); +// start_cheat_caller_address(launchpad.contract_address, sender_address); + +// launchpad.set_dollar_paid_finish_percentage(50_u256); +// } - // -// Unit test -// +// #[test] +// #[should_panic(expected: ('Caller is missing role',))] +// fn test_set_threshold_liquidity_non_admin() { +// let (_, _, launchpad) = request_fixture(); +// start_cheat_caller_address(launchpad.contract_address, ALICE()); -} +// launchpad.set_threshold_liquidity(50_u256); +// } + +// #[test] +// fn test_set_threshold_liquidity_ok() { +// let (sender_address, _, launchpad) = request_fixture(); +// start_cheat_caller_address(launchpad.contract_address, sender_address); + +// launchpad.set_threshold_liquidity(50_u256); +// } + +// #[test] +// #[should_panic(expected: ('Caller is missing role',))] +// fn test_set_address_jediswap_factory_v2_non_admin() { +// let (_, _, launchpad) = request_fixture(); +// start_cheat_caller_address(launchpad.contract_address, ALICE()); + +// launchpad.set_address_jediswap_factory_v2('jediswap'.try_into().unwrap()); +// } + +// #[test] +// fn test_set_address_jediswap_factory_v2_ok() { +// let (sender_address, _, launchpad) = request_fixture(); +// let mut spy = spy_events(); +// let jediswap_v2_addr: ContractAddress = 'jediswap'.try_into().unwrap(); + +// start_cheat_caller_address(launchpad.contract_address, sender_address); + +// launchpad.set_address_jediswap_factory_v2(jediswap_v2_addr); + +// let expected_event = LaunchpadEvent::SetJediswapV2Factory( +// SetJediswapV2Factory { address_jediswap_factory_v2: jediswap_v2_addr } +// ); +// spy.assert_emitted(@array![(launchpad.contract_address, expected_event)]); +// } + +// #[test] +// #[should_panic(expected: ('Caller is missing role',))] +// fn test_set_address_jediswap_nft_router_v2_non_admin() { +// let (_, _, launchpad) = request_fixture(); +// start_cheat_caller_address(launchpad.contract_address, ALICE()); + +// launchpad.set_address_jediswap_nft_router_v2('jediswap'.try_into().unwrap()); +// } + +// #[test] +// fn test_set_address_jediswap_nft_router_v2_ok() { +// let (sender_address, _, launchpad) = request_fixture(); +// let mut spy = spy_events(); +// let jediswap_nft_v2_addr: ContractAddress = 'jediswap'.try_into().unwrap(); + +// start_cheat_caller_address(launchpad.contract_address, sender_address); + +// launchpad.set_address_jediswap_nft_router_v2(jediswap_nft_v2_addr); + +// let expected_event = LaunchpadEvent::SetJediswapNFTRouterV2( +// SetJediswapNFTRouterV2 { address_jediswap_nft_router_v2: jediswap_nft_v2_addr } +// ); +// spy.assert_emitted(@array![(launchpad.contract_address, expected_event)]); +// } + +// #[test] +// #[should_panic(expected: ('Caller is missing role',))] +// fn test_set_exchanges_address_non_admin() { +// let (_, _, launchpad) = request_fixture(); +// let jediswap_addr: ContractAddress = 'jediswap'.try_into().unwrap(); +// start_cheat_caller_address(launchpad.contract_address, ALICE()); + +// let exchange_addresses = array![(SupportedExchanges::Jediswap, jediswap_addr)].span(); + +// launchpad.set_exchanges_address(exchange_addresses); +// } + +// #[test] +// fn test_set_exchanges_address_ok() { +// let (sender_address, _, launchpad) = request_fixture(); +// let jediswap_addr: ContractAddress = 'jediswap'.try_into().unwrap(); +// start_cheat_caller_address(launchpad.contract_address, sender_address); + +// let exchange_addresses = array![(SupportedExchanges::Jediswap, jediswap_addr)].span(); + +// launchpad.set_exchanges_address(exchange_addresses); +// } + +// #[test] +// #[should_panic(expected: ('Caller is missing role',))] +// fn test_set_class_hash_non_admin() { +// let (_, _, launchpad) = request_fixture(); +// start_cheat_caller_address(launchpad.contract_address, ALICE()); + +// launchpad.set_class_hash(class_hash_const::<'hash'>()); +// } + +// #[test] +// fn test_set_class_hash_ok() { +// let (sender_address, _, launchpad) = request_fixture(); +// start_cheat_caller_address(launchpad.contract_address, sender_address); + +// launchpad.set_class_hash(class_hash_const::<'hash'>()); +// } + +// #[test] +// #[should_panic(expected: ('coin not found',))] +// fn test_sell_coin_for_invalid_coin() { +// let (_, erc20, launchpad) = request_fixture(); + +// launchpad.sell_coin(erc20.contract_address, 50_u256); +// } + + +// #[test] +// // #[fork("Mainnet")] +// fn launchpad_test_calculation() { +// println!("launchpad_test_calculation"); +// let (sender_address, erc20, launchpad) = request_fixture(); +// start_cheat_caller_address_global(sender_address); +// start_cheat_caller_address(erc20.contract_address, sender_address); +// let default_token = launchpad.get_default_token(); +// assert(default_token.token_address == erc20.contract_address, 'no default token'); +// assert(default_token.starting_price == INITIAL_KEY_PRICE, 'no init price'); +// start_cheat_caller_address(launchpad.contract_address, sender_address); + +// let token_address = default_token.token_address; +// let amount_to_buy = THRESHOLD_LIQUIDITY; +// let amount_coin_get = run_calculation( +// launchpad, amount_to_buy, token_address, sender_address, false, true +// ); + +// println!("amount coin get {:?}", amount_coin_get); + +// let amount_coin_sell = run_calculation( +// launchpad, amount_to_buy, token_address, sender_address, true, true +// ); +// println!("amount_coin_sell {:?}", amount_coin_sell); +// assert!(amount_coin_get == amount_coin_sell, "amount incorrect"); +// } + +// #[test] +// fn test_get_coin_amount_by_quote_amount_for_buy_steps() { +// let (sender_address, erc20, launchpad) = request_fixture(); + +// start_cheat_caller_address(launchpad.contract_address, sender_address); + +// let token_address = launchpad +// .create_and_launch_token( +// symbol: SYMBOL(), +// name: NAME(), +// initial_supply: DEFAULT_INITIAL_SUPPLY(), +// contract_address_salt: SALT(), +// is_unruggable: false, +// ); + +// let memecoin = IERC20Dispatcher { contract_address: token_address }; + +// let mut quote_amount: u256 = 1; // Example amount of quote token for buying + +// // TODO calculation of amount received +// let expected_meme_amount_max: u256 = DEFAULT_INITIAL_SUPPLY() +// / LIQUIDITY_RATIO; // Replace with the expected value from the formula + +// let expected_meme_amount: u256 = expected_meme_amount_max +// / 10_u256; // Replace with the expected value from the formula + +// let result = launchpad.get_coin_amount_by_quote_amount(token_address, quote_amount, false,); + +// println!("result {:?}", result); +// println!("expected_meme_amount {:?}", expected_meme_amount); + +// run_buy_by_amount(launchpad, erc20, memecoin, quote_amount, token_address, sender_address,); +// let quote_amount_2: u256 = 1; // Example amount of quote token for buying +// assert(result == expected_meme_amount, 'Error: Buy calculation mismatch'); + +// println!("result {:?}", result); +// println!("expected_meme_amount {:?}", expected_meme_amount); + +// let share_key = launchpad.get_share_key_of_user(sender_address, memecoin.contract_address); + +// assert(share_key.owner == sender_address, 'wrong owner'); +// assert(share_key.amount_owned == result, 'wrong result'); +// assert(share_key.amount_owned == expected_meme_amount, 'wrong expected'); + +// let result = launchpad +// .get_coin_amount_by_quote_amount(token_address, quote_amount_2, false,); +// } +// // #[test] +// // // #[fork("Mainnet")] +// // fn test_launch_liquidity_ok() { +// // let (sender_address, erc20, launchpad) = request_fixture(); + +// // start_cheat_caller_address(launchpad.contract_address, OWNER()); + +// // let token_address = launchpad +// // .create_and_launch_token( +// // symbol: SYMBOL(), +// // name: NAME(), +// // initial_supply: DEFAULT_INITIAL_SUPPLY(), +// // contract_address_salt: SALT(), +// // is_unruggable: false +// // ); + +// // let memecoin = IERC20Dispatcher { contract_address: token_address }; + +// // run_buy_by_amount( +// // launchpad, erc20, memecoin, THRESHOLD_LIQUIDITY, token_address, sender_address, +// // ); + +// // launchpad.launch_liquidity(token_address); +// // } + +// // #[test] +// // #[fork("Mainnet")] +// // fn launchpad_buy_all_few_steps() { +// // println!("launchpad_buy_all_few_steps"); +// // let (sender_address, erc20, launchpad) = request_fixture(); +// // start_cheat_caller_address_global(sender_address); +// // start_cheat_caller_address(erc20.contract_address, sender_address); +// // // Call a view function of the contract +// // // Check default token used +// // let default_token = launchpad.get_default_token(); +// // assert(default_token.token_address == erc20.contract_address, 'no default token'); +// // assert(default_token.starting_price == INITIAL_KEY_PRICE, 'no init price'); +// // start_cheat_caller_address(launchpad.contract_address, sender_address); +// // println!("create and launch token"); +// // let token_address = launchpad +// // .create_and_launch_token( +// // // owner: OWNER(), +// // symbol: SYMBOL(), +// // name: NAME(), +// // initial_supply: DEFAULT_INITIAL_SUPPLY(), +// // contract_address_salt: SALT(), +// // ); +// // println!("test token_address {:?}", token_address); +// // let memecoin = IERC20Dispatcher { contract_address: token_address }; + +// // // All buy +// // let mut first_buy = 10_u256; + +// // run_buy_by_amount(launchpad, erc20, memecoin, first_buy, token_address, sender_address,); + +// // // run_buy_by_amount(launchpad, erc20, memecoin, first_buy, token_address, +// // sender_address,); + +// // run_buy_by_amount( +// // launchpad, +// // erc20, +// // memecoin, +// // THRESHOLD_LIQUIDITY - first_buy, +// // token_address, +// // sender_address, +// // ); +// // } +// // #[test] +// // #[fork("Mainnet")] +// // fn launchpad_buy_and_sell() { +// // println!("launchpad_buy_and_sell"); +// // let (sender_address, erc20, launchpad) = request_fixture(); +// // // let amount_key_buy = 1_u256; +// // start_cheat_caller_address_global(sender_address); +// // start_cheat_caller_address(erc20.contract_address, sender_address); +// // // Call a view function of the contract +// // // Check default token used +// // let default_token = launchpad.get_default_token(); +// // assert(default_token.token_address == erc20.contract_address, 'no default token'); +// // assert(default_token.starting_price == INITIAL_KEY_PRICE, 'no init price'); + +// // start_cheat_caller_address(launchpad.contract_address, sender_address); + +// // println!("create and launch token"); +// // let token_address = launchpad +// // .create_and_launch_token( +// // // owner: OWNER(), +// // symbol: SYMBOL(), +// // name: NAME(), +// // initial_supply: DEFAULT_INITIAL_SUPPLY(), +// // contract_address_salt: SALT(), +// // ); +// // println!("test token_address {:?}", token_address); + +// // let memecoin = IERC20Dispatcher { contract_address: token_address }; +// // let amount_first_buy = 10_u256; + +// // // // First buy with 10 quote token +// // run_buy_by_amount( +// // launchpad, erc20, memecoin, amount_first_buy, token_address, sender_address, +// // ); +// // // let mut total_amount_buy = amount_first_buy; + +// // let new_amount = THRESHOLD_LIQUIDITY - amount_first_buy; +// // // // First sell with 10 quote token +// // run_sell_by_amount( +// // launchpad, erc20, memecoin, amount_first_buy, token_address, sender_address, +// // ); +// // // // Threshold buy - 1 +// // // run_buy_by_amount( +// // // launchpad, erc20, memecoin, new_amount, token_address, sender_address, +// // // ); + +// // } + +// // #[test] +// // #[fork("Mainnet")] +// // #[should_panic(expected: ('threshold liquidity exceeded',))] +// // fn launchpad_buy_more_then_liquidity_threshold() { +// // println!("launchpad_buy_more_then_liquidity_threshold"); +// // let (sender_address, erc20, launchpad) = request_fixture(); +// // start_cheat_caller_address_global(sender_address); +// // start_cheat_caller_address(erc20.contract_address, sender_address); +// // let default_token = launchpad.get_default_token(); +// // assert(default_token.token_address == erc20.contract_address, 'no default token'); +// // assert(default_token.starting_price == INITIAL_KEY_PRICE, 'no init price'); +// // start_cheat_caller_address(launchpad.contract_address, sender_address); + +// // let token_address = launchpad +// // .create_token( +// // recipient: OWNER(), +// // // owner: OWNER(), +// // symbol: SYMBOL(), +// // name: NAME(), +// // initial_supply: DEFAULT_INITIAL_SUPPLY(), +// // contract_address_salt: SALT(), +// // ); +// // // println!("test token_address {:?}", token_address); +// // let memecoin = IERC20Dispatcher { contract_address: token_address }; +// // start_cheat_caller_address(memecoin.contract_address, sender_address); + +// // let balance_contract = memecoin.balance_of(launchpad.contract_address); +// // println!("test balance_contract {:?}", balance_contract); + +// // let total_supply = memecoin.total_supply(); +// // println!(" memecoin total_supply {:?}", total_supply); +// // memecoin.approve(launchpad.contract_address, total_supply); + +// // let allowance = memecoin.allowance(sender_address, launchpad.contract_address); +// // println!("test allowance meme coin{}", allowance); +// // // memecoin.transfer(launchpad.contract_address, total_supply); +// // stop_cheat_caller_address(memecoin.contract_address); + +// // start_cheat_caller_address(launchpad.contract_address, sender_address); + +// // launchpad.launch_token(token_address); +// // let amount_first_buy = 9_u256; + +// // run_buy_by_amount( +// // launchpad, erc20, memecoin, amount_first_buy, token_address, sender_address, +// // ); +// // // let mut total_amount_buy = amount_first_buy; + +// // let mut amount_second = 2_u256; +// // run_buy_by_amount( +// // launchpad, erc20, memecoin, amount_second, token_address, sender_address, +// // ); +// // // // // First buy with 10 quote token +// // // let res = run_sell_by_amount( +// // // launchpad, erc20, memecoin, amount_first_buy, token_address, sender_address, +// // // ); + +// // // // Final buy +// // // let res = run_buy_by_amount( +// // // launchpad, +// // // erc20, +// // // memecoin, +// // // THRESHOLD_LIQUIDITY - total_amount_buy, +// // // token_address, +// // // sender_address, +// // // ); +// // } + +// // +// // Unit test +// // + +// } diff --git a/onchain/cairo/src/tests/nameservice_tests.cairo b/onchain/cairo/src/tests/nameservice_tests.cairo index 897d061d..2cec9389 100644 --- a/onchain/cairo/src/tests/nameservice_tests.cairo +++ b/onchain/cairo/src/tests/nameservice_tests.cairo @@ -321,13 +321,16 @@ mod nameservice_tests { #[test] fn test_place_order() { let (nameservice_dispatcher, payment_token_dispatcher, payment_token_mintable_dispatcher) = - setup(); + setup(); + let MINTER_ROLE: felt252 = selector!("MINTER_ROLE"); start_cheat_caller_address(payment_token_mintable_dispatcher.contract_address, ADMIN()); payment_token_mintable_dispatcher .set_role(recipient: ADMIN(), role: MINTER_ROLE, is_enable: true); - payment_token_mintable_dispatcher.mint(CALLER(), 20_u256); + payment_token_mintable_dispatcher.mint(CALLER(), 20_u256); // Reduced amount + payment_token_mintable_dispatcher.mint(NEW_CALLER(), 20_u256); // Reduced amount + payment_token_mintable_dispatcher.mint(THIRD_CALLER(), 20_u256); // Reduced amount stop_cheat_caller_address(payment_token_mintable_dispatcher.contract_address); start_cheat_caller_address(payment_token_dispatcher.contract_address, CALLER()); @@ -341,19 +344,158 @@ mod nameservice_tests { let username = selector!("test"); start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); nameservice_dispatcher.claim_username(username); - nameservice_dispatcher.create_auction_for_username(username, 100_u256, false); stop_cheat_caller_address(nameservice_dispatcher.contract_address); - start_cheat_caller_address(nameservice_dispatcher.contract_address, NEW_CALLER()); - nameservice_dispatcher.place_order(username, 200_u256); + start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); + nameservice_dispatcher.create_auction_for_username(username, 5_u256, false); stop_cheat_caller_address(nameservice_dispatcher.contract_address); - start_cheat_caller_address(nameservice_dispatcher.contract_address, THIRD_CALLER()); - nameservice_dispatcher.place_order(username, 150_u256); + start_cheat_caller_address(payment_token_dispatcher.contract_address, NEW_CALLER()); + payment_token_dispatcher.approve(nameservice_dispatcher.contract_address, 20_u256); + stop_cheat_caller_address(payment_token_dispatcher.contract_address); + start_cheat_caller_address(nameservice_dispatcher.contract_address, NEW_CALLER()); + nameservice_dispatcher.place_order(username, 15_u256); stop_cheat_caller_address(nameservice_dispatcher.contract_address); let existing_auction = nameservice_dispatcher.get_auction(username); - assert(existing_auction.highest_bid == 200, 'highest_bid not correct'); + assert(existing_auction.highest_bid == 15, 'highest_bid not correct'); assert(existing_auction.highest_bidder == NEW_CALLER(), 'highest_bidder not correct'); + + let caller_balance = payment_token_dispatcher.balance_of(CALLER()); + assert(caller_balance == 10_u256, 'balance incorrect'); + + let new_caller_balance = payment_token_dispatcher.balance_of(NEW_CALLER()); + println!("The new_caller_balance is : {}", new_caller_balance); + assert(new_caller_balance == 5_u256, 'balance incorrect'); + + let contract_balance = payment_token_dispatcher + .balance_of(nameservice_dispatcher.contract_address); + println!("The contract_balance is : {}", contract_balance); + + assert(contract_balance == 25_u256, 'token balance incorrect'); + } + + #[test] + fn test_place_order_three() { + let (nameservice_dispatcher, payment_token_dispatcher, payment_token_mintable_dispatcher) = + setup(); + + let MINTER_ROLE: felt252 = selector!("MINTER_ROLE"); + + start_cheat_caller_address(payment_token_mintable_dispatcher.contract_address, ADMIN()); + payment_token_mintable_dispatcher + .set_role(recipient: ADMIN(), role: MINTER_ROLE, is_enable: true); + payment_token_mintable_dispatcher.mint(CALLER(), 20_u256); // Reduced amount + payment_token_mintable_dispatcher.mint(NEW_CALLER(), 20_u256); // Reduced amount + payment_token_mintable_dispatcher.mint(THIRD_CALLER(), 20_u256); // Reduced amount + stop_cheat_caller_address(payment_token_mintable_dispatcher.contract_address); + + start_cheat_caller_address(nameservice_dispatcher.contract_address, ADMIN()); + nameservice_dispatcher.set_is_payment_enabled(true); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + let caller_balance = payment_token_dispatcher.balance_of(CALLER()); + let new_caller_balance = payment_token_dispatcher.balance_of(NEW_CALLER()); + let third_caller_balance = payment_token_dispatcher.balance_of(THIRD_CALLER()); + let contract_balance = payment_token_dispatcher + .balance_of(nameservice_dispatcher.contract_address); + println!("The contract_balance is : {}", contract_balance); + println!("The caller_balance is : {}", caller_balance); + println!("The new_caller_balance is : {}", new_caller_balance); + println!("The third_caller_balance is : {}", third_caller_balance); + + start_cheat_caller_address(payment_token_dispatcher.contract_address, CALLER()); + payment_token_dispatcher.approve(nameservice_dispatcher.contract_address, 20_u256); + stop_cheat_caller_address(payment_token_dispatcher.contract_address); + + let username = selector!("test"); + start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); + nameservice_dispatcher.claim_username(username); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); //10 + nameservice_dispatcher.create_auction_for_username(username, 5_u256, false); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + start_cheat_caller_address(payment_token_dispatcher.contract_address, NEW_CALLER()); //2 + payment_token_dispatcher.approve(nameservice_dispatcher.contract_address, 20_u256); + stop_cheat_caller_address(payment_token_dispatcher.contract_address); + start_cheat_caller_address(nameservice_dispatcher.contract_address, NEW_CALLER()); + nameservice_dispatcher.place_order(username, 10_u256); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + start_cheat_caller_address(payment_token_dispatcher.contract_address, THIRD_CALLER()); //5 + payment_token_dispatcher.approve(nameservice_dispatcher.contract_address, 20_u256); + stop_cheat_caller_address(payment_token_dispatcher.contract_address); + start_cheat_caller_address(nameservice_dispatcher.contract_address, THIRD_CALLER()); + nameservice_dispatcher.place_order(username, 15_u256); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + start_cheat_caller_address(nameservice_dispatcher.contract_address, NEW_CALLER()); + nameservice_dispatcher.place_order(username, 18_u256); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + let caller_balance = payment_token_dispatcher.balance_of(CALLER()); + let new_caller_balance = payment_token_dispatcher.balance_of(NEW_CALLER()); + let third_caller_balance = payment_token_dispatcher.balance_of(THIRD_CALLER()); + let contract_balance = payment_token_dispatcher + .balance_of(nameservice_dispatcher.contract_address); + println!("The contract_balance is : {}", contract_balance); + println!("The caller_balance is : {}", caller_balance); + println!("The new_caller_balance is : {}", new_caller_balance); + println!("The third_caller_balance is : {}", third_caller_balance); + assert(contract_balance == 43_u256, 'token balance incorrect'); + assert(caller_balance == 10_u256, 'caller balance incorrect'); + assert(new_caller_balance == 2_u256, 'new_caller balance incorrect'); + assert(third_caller_balance == 5_u256, 'third_caller balance incorrect'); + + } + + #[test] + #[should_panic(expected: 'Bid too low')] + fn test_place_order_fail() { + let (nameservice_dispatcher, payment_token_dispatcher, payment_token_mintable_dispatcher) = + setup(); + + let MINTER_ROLE: felt252 = selector!("MINTER_ROLE"); + + start_cheat_caller_address(payment_token_mintable_dispatcher.contract_address, ADMIN()); + payment_token_mintable_dispatcher + .set_role(recipient: ADMIN(), role: MINTER_ROLE, is_enable: true); + payment_token_mintable_dispatcher.mint(CALLER(), 20_u256); // Reduced amount + payment_token_mintable_dispatcher.mint(NEW_CALLER(), 20_u256); // Reduced amount + payment_token_mintable_dispatcher.mint(THIRD_CALLER(), 20_u256); // Reduced amount + stop_cheat_caller_address(payment_token_mintable_dispatcher.contract_address); + + start_cheat_caller_address(payment_token_dispatcher.contract_address, CALLER()); + payment_token_dispatcher.approve(nameservice_dispatcher.contract_address, 20_u256); + stop_cheat_caller_address(payment_token_dispatcher.contract_address); + + start_cheat_caller_address(nameservice_dispatcher.contract_address, ADMIN()); + nameservice_dispatcher.set_is_payment_enabled(true); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + let username = selector!("test"); + start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); + nameservice_dispatcher.claim_username(username); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); + nameservice_dispatcher.create_auction_for_username(username, 5_u256, false); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + start_cheat_caller_address(payment_token_dispatcher.contract_address, NEW_CALLER()); + payment_token_dispatcher.approve(nameservice_dispatcher.contract_address, 20_u256); + stop_cheat_caller_address(payment_token_dispatcher.contract_address); + start_cheat_caller_address(nameservice_dispatcher.contract_address, NEW_CALLER()); + nameservice_dispatcher.place_order(username, 15_u256); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + start_cheat_caller_address(payment_token_dispatcher.contract_address, THIRD_CALLER()); + payment_token_dispatcher.approve(nameservice_dispatcher.contract_address, 20_u256); + stop_cheat_caller_address(payment_token_dispatcher.contract_address); + start_cheat_caller_address(nameservice_dispatcher.contract_address, THIRD_CALLER()); + nameservice_dispatcher.place_order(username, 10_u256); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); } } From d466626668e949c66e69f5ea140adec9de4bda4d Mon Sep 17 00:00:00 2001 From: Hakeem Kazeem Date: Wed, 27 Nov 2024 09:59:56 +0100 Subject: [PATCH 3/9] cancel_order --- onchain/cairo/src/afk_id/nameservice.cairo | 41 ++++++-- .../cairo/src/interfaces/nameservice.cairo | 2 +- .../cairo/src/tests/nameservice_tests.cairo | 96 ++++++++++++++++--- 3 files changed, 118 insertions(+), 21 deletions(-) diff --git a/onchain/cairo/src/afk_id/nameservice.cairo b/onchain/cairo/src/afk_id/nameservice.cairo index ff8e877a..65d3cb65 100644 --- a/onchain/cairo/src/afk_id/nameservice.cairo +++ b/onchain/cairo/src/afk_id/nameservice.cairo @@ -118,7 +118,7 @@ pub mod Nameservice { auctions: Map::, orders: Map, order_count: Map, - order_return: Map::, + order_return: Map::>, subscription_price: u256, token_quote: ContractAddress, is_payment_enabled: bool, @@ -376,9 +376,9 @@ pub mod Nameservice { let bidder = get_caller_address(); let quote_token = self.token_quote.read(); - // check if new bidder alredy has an outbidded amount (still in the contract) - let bidder_amount = self.order_return.read(bidder); - self.order_return.entry(bidder).write(0); + // check if new bidder already has an outbidded amount for the username(still in the contract) + let bidder_amount = self.order_return.entry(bidder).entry(username).read(); + self.order_return.entry(bidder).entry(username).write(0); let new_amount = amount - bidder_amount; if self.is_payment_enabled.read() { @@ -387,7 +387,7 @@ pub mod Nameservice { } let order_id = self.order_count.read(username) + 1; - let new_order = Order { bidder: bidder, amount: new_amount }; + let new_order = Order { bidder: bidder, amount: amount }; let old_order = self.orders.read(username); @@ -395,14 +395,14 @@ pub mod Nameservice { self.orders.write(username, new_order); self.order_count.write(username, order_id); - let order_return_amount = self.order_return.read(old_order.bidder); - println!(" order_return_amount: {:?}", order_return_amount); - self.order_return.entry(old_order.bidder).write((order_return_amount + old_order.amount)); + let order_return_amount = self.order_return.entry(old_order.bidder).entry(username).read(); + self.order_return.entry(old_order.bidder).entry(username).write((order_return_amount + old_order.amount)); // Update auction if this is the highest bid let mut updated_auction = auction; updated_auction.highest_bid = amount; updated_auction.highest_bidder = bidder; + updated_auction.is_accepted_price_reached = true; self.auctions.write(username, updated_auction); } @@ -411,7 +411,30 @@ pub mod Nameservice { fn accept_order(ref self: ContractState, username: felt252, id: u64) {} // TODO - fn cancel_order(ref self: ContractState, username: felt252, id: u64) { + fn cancel_order(ref self: ContractState, username: felt252) { + let bidder = get_caller_address(); + let auction = self.auctions.read(username); + let order = self.orders.read(username); + + let order_return_amount = self.order_return.entry(bidder).entry(username).read(); + + assert((order.bidder == bidder) || (order_return_amount >= 0), 'Inactive cancel order'); + // Update auction if this is the highest bid + let mut amount = 0; + if order.bidder == bidder { + amount = order.amount; + let mut updated_auction = auction; + updated_auction.highest_bid = 0; + updated_auction.highest_bidder = contract_address_const::<0>(); + updated_auction.is_accepted_price_reached = false; + self.auctions.write(username, updated_auction); + + } else { + amount = order_return_amount; + } + + let token = IERC20Dispatcher { contract_address: self.token_quote.read() }; + token.transfer(bidder, amount); } fn get_auction(self: @ContractState, username: felt252) -> Auction { diff --git a/onchain/cairo/src/interfaces/nameservice.cairo b/onchain/cairo/src/interfaces/nameservice.cairo index 995e312f..166ed2ea 100644 --- a/onchain/cairo/src/interfaces/nameservice.cairo +++ b/onchain/cairo/src/interfaces/nameservice.cairo @@ -13,7 +13,7 @@ pub trait INameservice { is_accepted_price_reached: bool ); fn place_order(ref self: TContractState, username: felt252, amount: u256); - fn cancel_order(ref self: TContractState, username: felt252, id: u64); + fn cancel_order(ref self: TContractState, username: felt252); fn accept_order(ref self: TContractState, username: felt252, id: u64); fn get_username(self: @TContractState, address: ContractAddress) -> felt252; fn get_username_address(self: @TContractState, key: felt252) -> ContractAddress; diff --git a/onchain/cairo/src/tests/nameservice_tests.cairo b/onchain/cairo/src/tests/nameservice_tests.cairo index 2cec9389..69b18d3f 100644 --- a/onchain/cairo/src/tests/nameservice_tests.cairo +++ b/onchain/cairo/src/tests/nameservice_tests.cairo @@ -394,16 +394,6 @@ mod nameservice_tests { nameservice_dispatcher.set_is_payment_enabled(true); stop_cheat_caller_address(nameservice_dispatcher.contract_address); - let caller_balance = payment_token_dispatcher.balance_of(CALLER()); - let new_caller_balance = payment_token_dispatcher.balance_of(NEW_CALLER()); - let third_caller_balance = payment_token_dispatcher.balance_of(THIRD_CALLER()); - let contract_balance = payment_token_dispatcher - .balance_of(nameservice_dispatcher.contract_address); - println!("The contract_balance is : {}", contract_balance); - println!("The caller_balance is : {}", caller_balance); - println!("The new_caller_balance is : {}", new_caller_balance); - println!("The third_caller_balance is : {}", third_caller_balance); - start_cheat_caller_address(payment_token_dispatcher.contract_address, CALLER()); payment_token_dispatcher.approve(nameservice_dispatcher.contract_address, 20_u256); stop_cheat_caller_address(payment_token_dispatcher.contract_address); @@ -448,7 +438,6 @@ mod nameservice_tests { assert(caller_balance == 10_u256, 'caller balance incorrect'); assert(new_caller_balance == 2_u256, 'new_caller balance incorrect'); assert(third_caller_balance == 5_u256, 'third_caller balance incorrect'); - } #[test] @@ -498,4 +487,89 @@ mod nameservice_tests { nameservice_dispatcher.place_order(username, 10_u256); stop_cheat_caller_address(nameservice_dispatcher.contract_address); } + + #[test] + fn test_cancel_order() { + let (nameservice_dispatcher, payment_token_dispatcher, payment_token_mintable_dispatcher) = + setup(); + + let MINTER_ROLE: felt252 = selector!("MINTER_ROLE"); + + start_cheat_caller_address(payment_token_mintable_dispatcher.contract_address, ADMIN()); + payment_token_mintable_dispatcher + .set_role(recipient: ADMIN(), role: MINTER_ROLE, is_enable: true); + payment_token_mintable_dispatcher.mint(CALLER(), 20_u256); // Reduced amount + payment_token_mintable_dispatcher.mint(NEW_CALLER(), 20_u256); // Reduced amount + payment_token_mintable_dispatcher.mint(THIRD_CALLER(), 20_u256); // Reduced amount + stop_cheat_caller_address(payment_token_mintable_dispatcher.contract_address); + + start_cheat_caller_address(nameservice_dispatcher.contract_address, ADMIN()); + nameservice_dispatcher.set_is_payment_enabled(true); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + start_cheat_caller_address(payment_token_dispatcher.contract_address, CALLER()); + payment_token_dispatcher.approve(nameservice_dispatcher.contract_address, 20_u256); + stop_cheat_caller_address(payment_token_dispatcher.contract_address); + + let username = selector!("test"); + start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); + nameservice_dispatcher.claim_username(username); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); //10 + nameservice_dispatcher.create_auction_for_username(username, 5_u256, false); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + start_cheat_caller_address(payment_token_dispatcher.contract_address, NEW_CALLER()); //2 + payment_token_dispatcher.approve(nameservice_dispatcher.contract_address, 20_u256); + stop_cheat_caller_address(payment_token_dispatcher.contract_address); + start_cheat_caller_address(nameservice_dispatcher.contract_address, NEW_CALLER()); + nameservice_dispatcher.place_order(username, 10_u256); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + start_cheat_caller_address(payment_token_dispatcher.contract_address, THIRD_CALLER()); //5 + payment_token_dispatcher.approve(nameservice_dispatcher.contract_address, 20_u256); + stop_cheat_caller_address(payment_token_dispatcher.contract_address); + start_cheat_caller_address(nameservice_dispatcher.contract_address, THIRD_CALLER()); + nameservice_dispatcher.place_order(username, 15_u256); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + start_cheat_caller_address(nameservice_dispatcher.contract_address, NEW_CALLER()); + nameservice_dispatcher.place_order(username, 18_u256); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + let caller_balance = payment_token_dispatcher.balance_of(CALLER()); + let new_caller_balance = payment_token_dispatcher.balance_of(NEW_CALLER()); + let third_caller_balance = payment_token_dispatcher.balance_of(THIRD_CALLER()); + let contract_balance = payment_token_dispatcher + .balance_of(nameservice_dispatcher.contract_address); + assert(contract_balance == 43_u256, 'token balance incorrect'); + assert(caller_balance == 10_u256, 'caller balance incorrect'); + assert(new_caller_balance == 2_u256, 'new_caller balance incorrect'); + assert(third_caller_balance == 5_u256, 'third_caller balance incorrect'); + + + start_cheat_caller_address(nameservice_dispatcher.contract_address, THIRD_CALLER()); + nameservice_dispatcher.cancel_order(username); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + start_cheat_caller_address(nameservice_dispatcher.contract_address, NEW_CALLER()); + nameservice_dispatcher.cancel_order(username); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + let caller_balance = payment_token_dispatcher.balance_of(CALLER()); + let new_caller_balance = payment_token_dispatcher.balance_of(NEW_CALLER()); + let third_caller_balance = payment_token_dispatcher.balance_of(THIRD_CALLER()); + let contract_balance = payment_token_dispatcher + .balance_of(nameservice_dispatcher.contract_address); + println!("The contract_balance is : {}", contract_balance); + println!("The caller_balance is : {}", caller_balance); + println!("The new_caller_balance is : {}", new_caller_balance); + println!("The third_caller_balance is : {}", third_caller_balance); + assert(contract_balance == 10_u256, 'token balance incorrect'); + assert(caller_balance == 10_u256, 'caller balance incorrect'); + assert(new_caller_balance == 20_u256, 'new_caller balance incorrect'); + assert(third_caller_balance == 20_u256, 'third_caller balance incorrect'); + + } } From 98fb36065b739586c5099bcd6473cb48b331dd26 Mon Sep 17 00:00:00 2001 From: Hakeem Kazeem Date: Thu, 28 Nov 2024 13:38:28 +0100 Subject: [PATCH 4/9] accept_order --- onchain/cairo/src/afk_id/nameservice.cairo | 26 +++++++- .../cairo/src/interfaces/nameservice.cairo | 2 +- .../cairo/src/tests/nameservice_tests.cairo | 65 +++++++++++++++++++ 3 files changed, 91 insertions(+), 2 deletions(-) diff --git a/onchain/cairo/src/afk_id/nameservice.cairo b/onchain/cairo/src/afk_id/nameservice.cairo index 65d3cb65..f0f6161c 100644 --- a/onchain/cairo/src/afk_id/nameservice.cairo +++ b/onchain/cairo/src/afk_id/nameservice.cairo @@ -96,6 +96,7 @@ pub mod Nameservice { #[derive(Drop, Debug, Serde, Copy, starknet::Store, PartialEq)] pub struct Auction { + pub owner: ContractAddress, pub minimal_price: u256, pub is_accepted_price_reached: bool, pub highest_bid: u256, @@ -355,6 +356,7 @@ pub mod Nameservice { // Create a new auction let new_auction = Auction { + owner: caller_address, minimal_price: minimal_price, is_accepted_price_reached: is_accepted_price_reached, highest_bid: 0, @@ -408,7 +410,29 @@ pub mod Nameservice { // TODO - fn accept_order(ref self: ContractState, username: felt252, id: u64) {} + fn accept_order(ref self: ContractState, username: felt252) { + let caller = get_caller_address(); + + let auction = self.auctions.read(username); + assert(auction.owner == caller, 'Not the auction owner'); + + let order = self.orders.read(username); + let bidder = order.bidder; + + let token = IERC20Dispatcher { contract_address: self.token_quote.read() }; + token.transfer(caller, order.amount); + + self.usernames.entry(username).write(bidder); + self.user_to_username.entry(bidder).write(username); + + let username_storage_value = self.username_storage.entry(username).read(); + let mut updated_username_storage_value = username_storage_value; + updated_username_storage_value.owner = bidder; + updated_username_storage_value.username = username; + + self.erc20.burn(caller, 1_u256); + self.erc20.mint(bidder, 1_u256); + } // TODO fn cancel_order(ref self: ContractState, username: felt252) { diff --git a/onchain/cairo/src/interfaces/nameservice.cairo b/onchain/cairo/src/interfaces/nameservice.cairo index 166ed2ea..7246d83a 100644 --- a/onchain/cairo/src/interfaces/nameservice.cairo +++ b/onchain/cairo/src/interfaces/nameservice.cairo @@ -14,7 +14,7 @@ pub trait INameservice { ); fn place_order(ref self: TContractState, username: felt252, amount: u256); fn cancel_order(ref self: TContractState, username: felt252); - fn accept_order(ref self: TContractState, username: felt252, id: u64); + fn accept_order(ref self: TContractState, username: felt252); fn get_username(self: @TContractState, address: ContractAddress) -> felt252; fn get_username_address(self: @TContractState, key: felt252) -> ContractAddress; fn get_token_quote(self: @TContractState,) -> ContractAddress; diff --git a/onchain/cairo/src/tests/nameservice_tests.cairo b/onchain/cairo/src/tests/nameservice_tests.cairo index 69b18d3f..aeb14227 100644 --- a/onchain/cairo/src/tests/nameservice_tests.cairo +++ b/onchain/cairo/src/tests/nameservice_tests.cairo @@ -21,6 +21,7 @@ mod nameservice_tests { fn THIRD_CALLER() -> ContractAddress { starknet::contract_address_const::<4>() } + const ADMIN_ROLE: felt252 = selector!("ADMIN_ROLE"); const YEAR_IN_SECONDS: u64 = 31536000_u64; const PAYMENT_AMOUNT: felt252 = 10; @@ -572,4 +573,68 @@ mod nameservice_tests { assert(third_caller_balance == 20_u256, 'third_caller balance incorrect'); } + + #[test] + fn test_accept_order() { + let (nameservice_dispatcher, payment_token_dispatcher, payment_token_mintable_dispatcher) = + setup(); + + let MINTER_ROLE: felt252 = selector!("MINTER_ROLE"); + + start_cheat_caller_address(payment_token_mintable_dispatcher.contract_address, ADMIN()); + payment_token_mintable_dispatcher + .set_role(recipient: ADMIN(), role: MINTER_ROLE, is_enable: true); + payment_token_mintable_dispatcher.mint(CALLER(), 20_u256); // Reduced amount + payment_token_mintable_dispatcher.mint(NEW_CALLER(), 20_u256); // Reduced amount + payment_token_mintable_dispatcher.mint(THIRD_CALLER(), 20_u256); // Reduced amount + stop_cheat_caller_address(payment_token_mintable_dispatcher.contract_address); + + start_cheat_caller_address(nameservice_dispatcher.contract_address, ADMIN()); + nameservice_dispatcher.set_is_payment_enabled(true); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + start_cheat_caller_address(payment_token_dispatcher.contract_address, CALLER()); + payment_token_dispatcher.approve(nameservice_dispatcher.contract_address, 20_u256); + stop_cheat_caller_address(payment_token_dispatcher.contract_address); + + let username = selector!("test"); + start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); + nameservice_dispatcher.claim_username(username); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + let stored_username = nameservice_dispatcher.get_username(CALLER()); + assert(stored_username == username, 'Username not set'); + + let stored_address = nameservice_dispatcher.get_username_address(username); + assert(stored_address == CALLER(), 'Address not set'); + + start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); //10 + nameservice_dispatcher.create_auction_for_username(username, 5_u256, false); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + start_cheat_caller_address(payment_token_dispatcher.contract_address, NEW_CALLER()); //2 + payment_token_dispatcher.approve(nameservice_dispatcher.contract_address, 20_u256); + stop_cheat_caller_address(payment_token_dispatcher.contract_address); + start_cheat_caller_address(nameservice_dispatcher.contract_address, NEW_CALLER()); + nameservice_dispatcher.place_order(username, 10_u256); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); + nameservice_dispatcher.accept_order(username); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + let stored_username = nameservice_dispatcher.get_username(NEW_CALLER()); + assert(stored_username == username, 'Username not set'); + + let stored_address = nameservice_dispatcher.get_username_address(username); + assert(stored_address == NEW_CALLER(), 'Address not set'); + + let caller_balance = payment_token_dispatcher.balance_of(CALLER()); + let new_caller_balance = payment_token_dispatcher.balance_of(NEW_CALLER()); + let contract_balance = payment_token_dispatcher + .balance_of(nameservice_dispatcher.contract_address); + assert(contract_balance == 10_u256, 'token balance incorrect'); + assert(caller_balance == 20_u256, 'caller balance incorrect'); + assert(new_caller_balance == 10_u256, 'new_caller balance incorrect'); + } } From 3c60e29b09d20a9f8b866d47f49f74b8a18f78e8 Mon Sep 17 00:00:00 2001 From: Hakeem Kazeem Date: Thu, 28 Nov 2024 17:54:18 +0100 Subject: [PATCH 5/9] events and more test --- .../cairo/.snfoundry_cache/.prev_tests_failed | 1 - onchain/cairo/src/afk_id/nameservice.cairo | 59 +++++++++++++++---- .../cairo/src/tests/nameservice_tests.cairo | 53 ++++++++++++++++- 3 files changed, 99 insertions(+), 14 deletions(-) diff --git a/onchain/cairo/.snfoundry_cache/.prev_tests_failed b/onchain/cairo/.snfoundry_cache/.prev_tests_failed index 5a186e86..e69de29b 100644 --- a/onchain/cairo/.snfoundry_cache/.prev_tests_failed +++ b/onchain/cairo/.snfoundry_cache/.prev_tests_failed @@ -1 +0,0 @@ -afk::tests::launchpad_tests::launchpad_tests::test_buy_coin_with_different_supply \ No newline at end of file diff --git a/onchain/cairo/src/afk_id/nameservice.cairo b/onchain/cairo/src/afk_id/nameservice.cairo index f0f6161c..b8f03a71 100644 --- a/onchain/cairo/src/afk_id/nameservice.cairo +++ b/onchain/cairo/src/afk_id/nameservice.cairo @@ -7,6 +7,12 @@ pub mod UserNameClaimErrors { pub const INVALID_PRICE: felt252 = 'Invalid price setting'; pub const INVALID_USERNAME: felt252 = 'Invalid username format'; pub const INVALID_DOMAIN_SUFFIX: felt252 = 'Domain must end with .afk'; + pub const AUCTION_DOESNT_EXIST: felt252 = 'Auction does not exist'; + pub const USER_NOT_OWNER: felt252 = 'User not owner'; + pub const BID_LOW: felt252 = 'Bid too low'; + pub const INVALID_CANCEL_ORDER: felt252 = 'Invalid cancel order'; + pub const USER_NOT_AUCTION_OWNER: felt252 = 'Not the auction owner'; + } const ADMIN_ROLE: felt252 = selector!("ADMIN_ROLE"); @@ -148,6 +154,7 @@ pub mod Nameservice { UsernameChanged: UsernameChanged, SubscriptionRenewed: SubscriptionRenewed, PriceUpdated: PriceUpdated, + AuctionCreated: AuctionCreated, #[flat] AccessControlEvent: AccessControlComponent::Event, #[flat] @@ -195,6 +202,15 @@ pub mod Nameservice { new_price: u256 } + #[derive(Drop, starknet::Event)] + struct AuctionCreated { + #[key] + owner: ContractAddress, + username: felt252, + minimal_price: u256, + is_accepted_price_reached: bool + + } // Required for hash computation. pub impl SNIP12MetadataImpl of SNIP12Metadata { @@ -349,10 +365,16 @@ pub mod Nameservice { let caller_address = get_caller_address(); let username_address = self.get_username_address(username); - assert(username_address == caller_address, 'Username not callers'); + assert( + username_address == caller_address, + UserNameClaimErrors::USER_NOT_OWNER + ); let existing_auction = self.auctions.read(username); - assert(existing_auction.minimal_price == 0, 'Auction does not exist'); + assert( + existing_auction.minimal_price == 0, + UserNameClaimErrors::AUCTION_DOESNT_EXIST + ); // Create a new auction let new_auction = Auction { @@ -365,14 +387,26 @@ pub mod Nameservice { // Store the auction self.auctions.write(username, new_auction); + self + .emit( + AuctionCreated { + owner: caller_address, + username: username, + minimal_price, + is_accepted_price_reached + } + ); } // TODO fn place_order(ref self: ContractState, username: felt252, amount: u256) { let auction = self.auctions.read(username); - assert(auction.minimal_price > 0, 'Auction does not exist'); - assert(amount > auction.highest_bid, 'Bid too low'); + assert( + auction.minimal_price > 0, + UserNameClaimErrors::AUCTION_DOESNT_EXIST + ); + assert(amount > auction.highest_bid, UserNameClaimErrors::BID_LOW); // Create a new order let bidder = get_caller_address(); @@ -381,11 +415,12 @@ pub mod Nameservice { // check if new bidder already has an outbidded amount for the username(still in the contract) let bidder_amount = self.order_return.entry(bidder).entry(username).read(); self.order_return.entry(bidder).entry(username).write(0); - let new_amount = amount - bidder_amount; - if self.is_payment_enabled.read() { - let payment_token = IERC20Dispatcher { contract_address: quote_token }; - payment_token.transfer_from(bidder, get_contract_address(), new_amount); + if amount > bidder_amount { + if self.is_payment_enabled.read() { + let payment_token = IERC20Dispatcher { contract_address: quote_token }; + payment_token.transfer_from(bidder, get_contract_address(), (amount - bidder_amount)); + } } let order_id = self.order_count.read(username) + 1; @@ -414,7 +449,7 @@ pub mod Nameservice { let caller = get_caller_address(); let auction = self.auctions.read(username); - assert(auction.owner == caller, 'Not the auction owner'); + assert(auction.owner == caller, UserNameClaimErrors::USER_NOT_AUCTION_OWNER); let order = self.orders.read(username); let bidder = order.bidder; @@ -430,8 +465,8 @@ pub mod Nameservice { updated_username_storage_value.owner = bidder; updated_username_storage_value.username = username; - self.erc20.burn(caller, 1_u256); - self.erc20.mint(bidder, 1_u256); + // self.erc20.burn(caller, 1_u256); + // self.erc20.mint(bidder, 1_u256); } // TODO @@ -442,7 +477,7 @@ pub mod Nameservice { let order_return_amount = self.order_return.entry(bidder).entry(username).read(); - assert((order.bidder == bidder) || (order_return_amount >= 0), 'Inactive cancel order'); + assert((order.bidder == bidder) || (order_return_amount >= 0), UserNameClaimErrors::INVALID_CANCEL_ORDER); // Update auction if this is the highest bid let mut amount = 0; if order.bidder == bidder { diff --git a/onchain/cairo/src/tests/nameservice_tests.cairo b/onchain/cairo/src/tests/nameservice_tests.cairo index aeb14227..c2b8053f 100644 --- a/onchain/cairo/src/tests/nameservice_tests.cairo +++ b/onchain/cairo/src/tests/nameservice_tests.cairo @@ -293,7 +293,7 @@ mod nameservice_tests { } #[test] - #[should_panic(expected: 'Username not callers')] + #[should_panic(expected: 'User not owner')] fn test_create_auction_for_username_fail() { let (nameservice_dispatcher, payment_token_dispatcher, payment_token_mintable_dispatcher) = setup(); @@ -637,4 +637,55 @@ mod nameservice_tests { assert(caller_balance == 20_u256, 'caller balance incorrect'); assert(new_caller_balance == 10_u256, 'new_caller balance incorrect'); } + + #[test] + #[should_panic(expected: 'Not the auction owner')] + fn test_accept_order_fail() { + let (nameservice_dispatcher, payment_token_dispatcher, payment_token_mintable_dispatcher) = + setup(); + + let MINTER_ROLE: felt252 = selector!("MINTER_ROLE"); + + start_cheat_caller_address(payment_token_mintable_dispatcher.contract_address, ADMIN()); + payment_token_mintable_dispatcher + .set_role(recipient: ADMIN(), role: MINTER_ROLE, is_enable: true); + payment_token_mintable_dispatcher.mint(CALLER(), 20_u256); // Reduced amount + payment_token_mintable_dispatcher.mint(NEW_CALLER(), 20_u256); // Reduced amount + payment_token_mintable_dispatcher.mint(THIRD_CALLER(), 20_u256); // Reduced amount + stop_cheat_caller_address(payment_token_mintable_dispatcher.contract_address); + + start_cheat_caller_address(nameservice_dispatcher.contract_address, ADMIN()); + nameservice_dispatcher.set_is_payment_enabled(true); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + start_cheat_caller_address(payment_token_dispatcher.contract_address, CALLER()); + payment_token_dispatcher.approve(nameservice_dispatcher.contract_address, 20_u256); + stop_cheat_caller_address(payment_token_dispatcher.contract_address); + + let username = selector!("test"); + start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); + nameservice_dispatcher.claim_username(username); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + let stored_username = nameservice_dispatcher.get_username(CALLER()); + assert(stored_username == username, 'Username not set'); + + let stored_address = nameservice_dispatcher.get_username_address(username); + assert(stored_address == CALLER(), 'Address not set'); + + start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); //10 + nameservice_dispatcher.create_auction_for_username(username, 5_u256, false); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + start_cheat_caller_address(payment_token_dispatcher.contract_address, NEW_CALLER()); //2 + payment_token_dispatcher.approve(nameservice_dispatcher.contract_address, 20_u256); + stop_cheat_caller_address(payment_token_dispatcher.contract_address); + start_cheat_caller_address(nameservice_dispatcher.contract_address, NEW_CALLER()); + nameservice_dispatcher.place_order(username, 10_u256); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + start_cheat_caller_address(nameservice_dispatcher.contract_address, THIRD_CALLER()); + nameservice_dispatcher.accept_order(username); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + } } From 019668b17e5f7b78e60d61c475640bbec432f648 Mon Sep 17 00:00:00 2001 From: Hakeem Kazeem Date: Thu, 28 Nov 2024 20:55:55 +0100 Subject: [PATCH 6/9] mint, burn in accept order --- onchain/cairo/src/afk_id/nameservice.cairo | 6 +++--- onchain/cairo/src/tests/nameservice_tests.cairo | 13 ------------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/onchain/cairo/src/afk_id/nameservice.cairo b/onchain/cairo/src/afk_id/nameservice.cairo index b8f03a71..8a30f400 100644 --- a/onchain/cairo/src/afk_id/nameservice.cairo +++ b/onchain/cairo/src/afk_id/nameservice.cairo @@ -355,6 +355,7 @@ pub mod Nameservice { // TODO change main username fn change_main_username(ref self: ContractState, new_username: felt252) {} + // TODO fn create_auction_for_username( ref self: ContractState, @@ -400,7 +401,6 @@ pub mod Nameservice { // TODO fn place_order(ref self: ContractState, username: felt252, amount: u256) { - let auction = self.auctions.read(username); assert( auction.minimal_price > 0, @@ -465,8 +465,8 @@ pub mod Nameservice { updated_username_storage_value.owner = bidder; updated_username_storage_value.username = username; - // self.erc20.burn(caller, 1_u256); - // self.erc20.mint(bidder, 1_u256); + self.erc20.burn(caller, 1_u256); + self.erc20.mint(bidder, 1_u256); } // TODO diff --git a/onchain/cairo/src/tests/nameservice_tests.cairo b/onchain/cairo/src/tests/nameservice_tests.cairo index c2b8053f..309a9223 100644 --- a/onchain/cairo/src/tests/nameservice_tests.cairo +++ b/onchain/cairo/src/tests/nameservice_tests.cairo @@ -121,8 +121,6 @@ mod nameservice_tests { let contract_balance = payment_token_dispatcher .balance_of(nameservice_dispatcher.contract_address); - println!("The contract_balance is : {}", contract_balance); - assert(contract_balance == 10_u256, 'token balance incorrect'); } @@ -366,13 +364,10 @@ mod nameservice_tests { assert(caller_balance == 10_u256, 'balance incorrect'); let new_caller_balance = payment_token_dispatcher.balance_of(NEW_CALLER()); - println!("The new_caller_balance is : {}", new_caller_balance); assert(new_caller_balance == 5_u256, 'balance incorrect'); let contract_balance = payment_token_dispatcher .balance_of(nameservice_dispatcher.contract_address); - println!("The contract_balance is : {}", contract_balance); - assert(contract_balance == 25_u256, 'token balance incorrect'); } @@ -431,10 +426,6 @@ mod nameservice_tests { let third_caller_balance = payment_token_dispatcher.balance_of(THIRD_CALLER()); let contract_balance = payment_token_dispatcher .balance_of(nameservice_dispatcher.contract_address); - println!("The contract_balance is : {}", contract_balance); - println!("The caller_balance is : {}", caller_balance); - println!("The new_caller_balance is : {}", new_caller_balance); - println!("The third_caller_balance is : {}", third_caller_balance); assert(contract_balance == 43_u256, 'token balance incorrect'); assert(caller_balance == 10_u256, 'caller balance incorrect'); assert(new_caller_balance == 2_u256, 'new_caller balance incorrect'); @@ -563,10 +554,6 @@ mod nameservice_tests { let third_caller_balance = payment_token_dispatcher.balance_of(THIRD_CALLER()); let contract_balance = payment_token_dispatcher .balance_of(nameservice_dispatcher.contract_address); - println!("The contract_balance is : {}", contract_balance); - println!("The caller_balance is : {}", caller_balance); - println!("The new_caller_balance is : {}", new_caller_balance); - println!("The third_caller_balance is : {}", third_caller_balance); assert(contract_balance == 10_u256, 'token balance incorrect'); assert(caller_balance == 10_u256, 'caller balance incorrect'); assert(new_caller_balance == 20_u256, 'new_caller balance incorrect'); From 28f1a83ada0a457f7a810310268edda4703b532c Mon Sep 17 00:00:00 2001 From: Hakeem Kazeem Date: Sat, 30 Nov 2024 15:13:22 +0100 Subject: [PATCH 7/9] change request --- onchain/cairo/src/afk_id/nameservice.cairo | 116 ++++++++++-------- .../cairo/src/interfaces/nameservice.cairo | 4 +- .../cairo/src/tests/nameservice_tests.cairo | 101 +++++++++++---- 3 files changed, 148 insertions(+), 73 deletions(-) diff --git a/onchain/cairo/src/afk_id/nameservice.cairo b/onchain/cairo/src/afk_id/nameservice.cairo index 8a30f400..f8363f4b 100644 --- a/onchain/cairo/src/afk_id/nameservice.cairo +++ b/onchain/cairo/src/afk_id/nameservice.cairo @@ -12,7 +12,8 @@ pub mod UserNameClaimErrors { pub const BID_LOW: felt252 = 'Bid too low'; pub const INVALID_CANCEL_ORDER: felt252 = 'Invalid cancel order'; pub const USER_NOT_AUCTION_OWNER: felt252 = 'Not the auction owner'; - + pub const ACCEPTED_PRICE_REACHED: felt252 = 'Accepted Price Reached'; + pub const ORDER_INACTIVE: felt252 = 'Order is Inactive'; } const ADMIN_ROLE: felt252 = selector!("ADMIN_ROLE"); @@ -100,19 +101,21 @@ pub mod Nameservice { pub is_claimed: bool } - #[derive(Drop, Debug, Serde, Copy, starknet::Store, PartialEq)] + #[derive(Drop, Debug, Serde, Copy, starknet::Store)] pub struct Auction { pub owner: ContractAddress, pub minimal_price: u256, pub is_accepted_price_reached: bool, pub highest_bid: u256, - pub highest_bidder: ContractAddress + pub highest_bidder: ContractAddress, } #[derive(Drop, Debug, Serde, Copy, starknet::Store, PartialEq)] struct Order { + id: u256, bidder: ContractAddress, amount: u256, + is_active: bool } #[storage] @@ -123,8 +126,8 @@ pub mod Nameservice { subscription_expiry: Map::, username_storage: Map::, auctions: Map::, - orders: Map, - order_count: Map, + orders: Map::<(felt252, u256), Order>, + order_count: Map::, order_return: Map::>, subscription_price: u256, token_quote: ContractAddress, @@ -372,6 +375,7 @@ pub mod Nameservice { ); let existing_auction = self.auctions.read(username); + // TODO change ERROR NAME assert( existing_auction.minimal_price == 0, UserNameClaimErrors::AUCTION_DOESNT_EXIST @@ -410,50 +414,64 @@ pub mod Nameservice { // Create a new order let bidder = get_caller_address(); - let quote_token = self.token_quote.read(); + // let quote_token = self.token_quote.read(); // check if new bidder already has an outbidded amount for the username(still in the contract) - let bidder_amount = self.order_return.entry(bidder).entry(username).read(); - self.order_return.entry(bidder).entry(username).write(0); - - if amount > bidder_amount { - if self.is_payment_enabled.read() { - let payment_token = IERC20Dispatcher { contract_address: quote_token }; - payment_token.transfer_from(bidder, get_contract_address(), (amount - bidder_amount)); - } - } + // let bidder_amount = self.order_return.entry(bidder).entry(username).read(); + // self.order_return.entry(bidder).entry(username).write(0); - let order_id = self.order_count.read(username) + 1; - let new_order = Order { bidder: bidder, amount: amount }; + // if amount > bidder_amount { + // if self.is_payment_enabled.read() { + // let payment_token = IERC20Dispatcher { contract_address: quote_token }; + // payment_token.transfer_from(bidder, get_contract_address(), (amount - bidder_amount)); + // } + // } - let old_order = self.orders.read(username); + let payment_token = IERC20Dispatcher { contract_address: self.token_quote.read() }; + payment_token.transfer_from(bidder, get_contract_address(), amount); - // Store the order - self.orders.write(username, new_order); - self.order_count.write(username, order_id); + let order_id = self.order_count.entry(username).read() + 1_u256; + let new_order = Order { id: order_id, bidder: bidder, amount: amount, is_active: true }; + + // let old_order = self.orders.read(username); - let order_return_amount = self.order_return.entry(old_order.bidder).entry(username).read(); - self.order_return.entry(old_order.bidder).entry(username).write((order_return_amount + old_order.amount)); + // Store the order + self.orders.entry((username, order_id)).write(new_order); + self.order_count.entry(username).write(order_id); // Update auction if this is the highest bid let mut updated_auction = auction; updated_auction.highest_bid = amount; updated_auction.highest_bidder = bidder; - updated_auction.is_accepted_price_reached = true; + updated_auction.is_accepted_price_reached = false; self.auctions.write(username, updated_auction); } - - + // TODO - fn accept_order(ref self: ContractState, username: felt252) { + fn accept_order(ref self: ContractState, username: felt252, id: u64) { let caller = get_caller_address(); + let id: u256 = id.into(); let auction = self.auctions.read(username); assert(auction.owner == caller, UserNameClaimErrors::USER_NOT_AUCTION_OWNER); + assert(auction.is_accepted_price_reached == false, UserNameClaimErrors::ACCEPTED_PRICE_REACHED); + + let order = self.orders.entry((username, id)).read(); + assert(order.is_active == true, UserNameClaimErrors::ORDER_INACTIVE); - let order = self.orders.read(username); let bidder = order.bidder; + // Update Order to inactive + let mut updated_order = order; + updated_order.is_active = false; + self.orders.entry((username, id)).write(order); + + // Update auction is_accepted_price_reached + let mut updated_auction = auction; + updated_auction.is_accepted_price_reached = true; + self.auctions.write(username, updated_auction); + + // Send token from contract to auction owner let token = IERC20Dispatcher { contract_address: self.token_quote.read() }; token.transfer(caller, order.amount); @@ -470,30 +488,29 @@ pub mod Nameservice { } // TODO - fn cancel_order(ref self: ContractState, username: felt252) { - let bidder = get_caller_address(); + fn cancel_order(ref self: ContractState, username: felt252, id: u64) { + let caller = get_caller_address(); let auction = self.auctions.read(username); - let order = self.orders.read(username); - - let order_return_amount = self.order_return.entry(bidder).entry(username).read(); - - assert((order.bidder == bidder) || (order_return_amount >= 0), UserNameClaimErrors::INVALID_CANCEL_ORDER); - // Update auction if this is the highest bid - let mut amount = 0; - if order.bidder == bidder { - amount = order.amount; - let mut updated_auction = auction; - updated_auction.highest_bid = 0; - updated_auction.highest_bidder = contract_address_const::<0>(); - updated_auction.is_accepted_price_reached = false; - self.auctions.write(username, updated_auction); - - } else { - amount = order_return_amount; - } + let id: u256 = id.into(); + let order = self.orders.entry((username, id)).read(); + + assert((order.bidder == caller), UserNameClaimErrors::INVALID_CANCEL_ORDER); + // Update order + let amount = order.amount; + let mut updated_order = order; + updated_order.amount = 0; + updated_order.is_active = false; + self.orders.entry((username, id)).write(updated_order); + + // Update auction if the caller is the highest bid + let mut updated_auction = auction; + updated_auction.highest_bid = 0; + updated_auction.highest_bidder = contract_address_const::<0>(); + updated_auction.is_accepted_price_reached = false; + self.auctions.write(username, updated_auction); let token = IERC20Dispatcher { contract_address: self.token_quote.read() }; - token.transfer(bidder, amount); + token.transfer(caller, amount); } fn get_auction(self: @ContractState, username: felt252) -> Auction { @@ -552,7 +569,6 @@ pub mod Nameservice { ); } - // ADMIN // Admin functions fn update_subscription_price(ref self: ContractState, new_price: u256) { diff --git a/onchain/cairo/src/interfaces/nameservice.cairo b/onchain/cairo/src/interfaces/nameservice.cairo index 7246d83a..995e312f 100644 --- a/onchain/cairo/src/interfaces/nameservice.cairo +++ b/onchain/cairo/src/interfaces/nameservice.cairo @@ -13,8 +13,8 @@ pub trait INameservice { is_accepted_price_reached: bool ); fn place_order(ref self: TContractState, username: felt252, amount: u256); - fn cancel_order(ref self: TContractState, username: felt252); - fn accept_order(ref self: TContractState, username: felt252); + fn cancel_order(ref self: TContractState, username: felt252, id: u64); + fn accept_order(ref self: TContractState, username: felt252, id: u64); fn get_username(self: @TContractState, address: ContractAddress) -> felt252; fn get_username_address(self: @TContractState, key: felt252) -> ContractAddress; fn get_token_quote(self: @TContractState,) -> ContractAddress; diff --git a/onchain/cairo/src/tests/nameservice_tests.cairo b/onchain/cairo/src/tests/nameservice_tests.cairo index 309a9223..ea229352 100644 --- a/onchain/cairo/src/tests/nameservice_tests.cairo +++ b/onchain/cairo/src/tests/nameservice_tests.cairo @@ -382,7 +382,7 @@ mod nameservice_tests { payment_token_mintable_dispatcher .set_role(recipient: ADMIN(), role: MINTER_ROLE, is_enable: true); payment_token_mintable_dispatcher.mint(CALLER(), 20_u256); // Reduced amount - payment_token_mintable_dispatcher.mint(NEW_CALLER(), 20_u256); // Reduced amount + payment_token_mintable_dispatcher.mint(NEW_CALLER(), 30_u256); // Reduced amount payment_token_mintable_dispatcher.mint(THIRD_CALLER(), 20_u256); // Reduced amount stop_cheat_caller_address(payment_token_mintable_dispatcher.contract_address); @@ -404,7 +404,7 @@ mod nameservice_tests { stop_cheat_caller_address(nameservice_dispatcher.contract_address); start_cheat_caller_address(payment_token_dispatcher.contract_address, NEW_CALLER()); //2 - payment_token_dispatcher.approve(nameservice_dispatcher.contract_address, 20_u256); + payment_token_dispatcher.approve(nameservice_dispatcher.contract_address, 30_u256); stop_cheat_caller_address(payment_token_dispatcher.contract_address); start_cheat_caller_address(nameservice_dispatcher.contract_address, NEW_CALLER()); nameservice_dispatcher.place_order(username, 10_u256); @@ -426,7 +426,7 @@ mod nameservice_tests { let third_caller_balance = payment_token_dispatcher.balance_of(THIRD_CALLER()); let contract_balance = payment_token_dispatcher .balance_of(nameservice_dispatcher.contract_address); - assert(contract_balance == 43_u256, 'token balance incorrect'); + assert(contract_balance == 53_u256, 'token balance incorrect'); assert(caller_balance == 10_u256, 'caller balance incorrect'); assert(new_caller_balance == 2_u256, 'new_caller balance incorrect'); assert(third_caller_balance == 5_u256, 'third_caller balance incorrect'); @@ -527,7 +527,7 @@ mod nameservice_tests { stop_cheat_caller_address(nameservice_dispatcher.contract_address); start_cheat_caller_address(nameservice_dispatcher.contract_address, NEW_CALLER()); - nameservice_dispatcher.place_order(username, 18_u256); + nameservice_dispatcher.cancel_order(username, 1); stop_cheat_caller_address(nameservice_dispatcher.contract_address); let caller_balance = payment_token_dispatcher.balance_of(CALLER()); @@ -535,34 +535,80 @@ mod nameservice_tests { let third_caller_balance = payment_token_dispatcher.balance_of(THIRD_CALLER()); let contract_balance = payment_token_dispatcher .balance_of(nameservice_dispatcher.contract_address); - assert(contract_balance == 43_u256, 'token balance incorrect'); + assert(contract_balance == 25_u256, 'token balance incorrect'); assert(caller_balance == 10_u256, 'caller balance incorrect'); - assert(new_caller_balance == 2_u256, 'new_caller balance incorrect'); + assert(new_caller_balance == 20_u256, 'new_caller balance incorrect'); assert(third_caller_balance == 5_u256, 'third_caller balance incorrect'); + } - start_cheat_caller_address(nameservice_dispatcher.contract_address, THIRD_CALLER()); - nameservice_dispatcher.cancel_order(username); + #[test] + fn test_accept_order() { + let (nameservice_dispatcher, payment_token_dispatcher, payment_token_mintable_dispatcher) = + setup(); + + let MINTER_ROLE: felt252 = selector!("MINTER_ROLE"); + + start_cheat_caller_address(payment_token_mintable_dispatcher.contract_address, ADMIN()); + payment_token_mintable_dispatcher + .set_role(recipient: ADMIN(), role: MINTER_ROLE, is_enable: true); + payment_token_mintable_dispatcher.mint(CALLER(), 20_u256); // Reduced amount + payment_token_mintable_dispatcher.mint(NEW_CALLER(), 20_u256); // Reduced amount + payment_token_mintable_dispatcher.mint(THIRD_CALLER(), 20_u256); // Reduced amount + stop_cheat_caller_address(payment_token_mintable_dispatcher.contract_address); + + start_cheat_caller_address(nameservice_dispatcher.contract_address, ADMIN()); + nameservice_dispatcher.set_is_payment_enabled(true); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + start_cheat_caller_address(payment_token_dispatcher.contract_address, CALLER()); + payment_token_dispatcher.approve(nameservice_dispatcher.contract_address, 20_u256); + stop_cheat_caller_address(payment_token_dispatcher.contract_address); + + let username = selector!("test"); + start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); + nameservice_dispatcher.claim_username(username); stop_cheat_caller_address(nameservice_dispatcher.contract_address); + let stored_username = nameservice_dispatcher.get_username(CALLER()); + assert(stored_username == username, 'Username not set'); + + let stored_address = nameservice_dispatcher.get_username_address(username); + assert(stored_address == CALLER(), 'Address not set'); + + start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); //10 + nameservice_dispatcher.create_auction_for_username(username, 5_u256, false); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + start_cheat_caller_address(payment_token_dispatcher.contract_address, NEW_CALLER()); //2 + payment_token_dispatcher.approve(nameservice_dispatcher.contract_address, 20_u256); + stop_cheat_caller_address(payment_token_dispatcher.contract_address); start_cheat_caller_address(nameservice_dispatcher.contract_address, NEW_CALLER()); - nameservice_dispatcher.cancel_order(username); + nameservice_dispatcher.place_order(username, 10_u256); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); + nameservice_dispatcher.accept_order(username, 1); stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + + let stored_username = nameservice_dispatcher.get_username(NEW_CALLER()); + assert(stored_username == username, 'Username not set'); + + let stored_address = nameservice_dispatcher.get_username_address(username); + assert(stored_address == NEW_CALLER(), 'Address not set'); let caller_balance = payment_token_dispatcher.balance_of(CALLER()); let new_caller_balance = payment_token_dispatcher.balance_of(NEW_CALLER()); - let third_caller_balance = payment_token_dispatcher.balance_of(THIRD_CALLER()); let contract_balance = payment_token_dispatcher .balance_of(nameservice_dispatcher.contract_address); assert(contract_balance == 10_u256, 'token balance incorrect'); - assert(caller_balance == 10_u256, 'caller balance incorrect'); - assert(new_caller_balance == 20_u256, 'new_caller balance incorrect'); - assert(third_caller_balance == 20_u256, 'third_caller balance incorrect'); - + assert(caller_balance == 20_u256, 'caller balance incorrect'); + assert(new_caller_balance == 10_u256, 'new_caller balance incorrect'); } #[test] - fn test_accept_order() { + fn test_accept_order_and_cancel_order() { let (nameservice_dispatcher, payment_token_dispatcher, payment_token_mintable_dispatcher) = setup(); @@ -606,23 +652,36 @@ mod nameservice_tests { nameservice_dispatcher.place_order(username, 10_u256); stop_cheat_caller_address(nameservice_dispatcher.contract_address); + start_cheat_caller_address(payment_token_dispatcher.contract_address, THIRD_CALLER()); //2 + payment_token_dispatcher.approve(nameservice_dispatcher.contract_address, 20_u256); + stop_cheat_caller_address(payment_token_dispatcher.contract_address); + start_cheat_caller_address(nameservice_dispatcher.contract_address, THIRD_CALLER()); + nameservice_dispatcher.place_order(username, 15_u256); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); - nameservice_dispatcher.accept_order(username); + nameservice_dispatcher.accept_order(username, 2); stop_cheat_caller_address(nameservice_dispatcher.contract_address); - let stored_username = nameservice_dispatcher.get_username(NEW_CALLER()); + start_cheat_caller_address(nameservice_dispatcher.contract_address, NEW_CALLER()); + nameservice_dispatcher.cancel_order(username, 1); + stop_cheat_caller_address(nameservice_dispatcher.contract_address); + + let stored_username = nameservice_dispatcher.get_username(THIRD_CALLER()); assert(stored_username == username, 'Username not set'); let stored_address = nameservice_dispatcher.get_username_address(username); - assert(stored_address == NEW_CALLER(), 'Address not set'); + assert(stored_address == THIRD_CALLER(), 'Address not set'); let caller_balance = payment_token_dispatcher.balance_of(CALLER()); let new_caller_balance = payment_token_dispatcher.balance_of(NEW_CALLER()); + let third_caller_balance = payment_token_dispatcher.balance_of(THIRD_CALLER()); let contract_balance = payment_token_dispatcher .balance_of(nameservice_dispatcher.contract_address); assert(contract_balance == 10_u256, 'token balance incorrect'); - assert(caller_balance == 20_u256, 'caller balance incorrect'); - assert(new_caller_balance == 10_u256, 'new_caller balance incorrect'); + assert(caller_balance == 25_u256, 'caller balance incorrect'); + assert(new_caller_balance == 20_u256, 'new_caller balance incorrect'); + assert(third_caller_balance == 5_u256, 'third_caller balance incorrect'); } #[test] @@ -672,7 +731,7 @@ mod nameservice_tests { stop_cheat_caller_address(nameservice_dispatcher.contract_address); start_cheat_caller_address(nameservice_dispatcher.contract_address, THIRD_CALLER()); - nameservice_dispatcher.accept_order(username); + nameservice_dispatcher.accept_order(username, 1); stop_cheat_caller_address(nameservice_dispatcher.contract_address); } } From eb96c5ccf37892dea77714ec83f6013bb683c7d8 Mon Sep 17 00:00:00 2001 From: Hakeem Kazeem Date: Sat, 30 Nov 2024 15:16:22 +0100 Subject: [PATCH 8/9] removed commented codes --- onchain/cairo/src/afk_id/nameservice.cairo | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/onchain/cairo/src/afk_id/nameservice.cairo b/onchain/cairo/src/afk_id/nameservice.cairo index f8363f4b..cd52055b 100644 --- a/onchain/cairo/src/afk_id/nameservice.cairo +++ b/onchain/cairo/src/afk_id/nameservice.cairo @@ -415,26 +415,12 @@ pub mod Nameservice { // Create a new order let bidder = get_caller_address(); - // let quote_token = self.token_quote.read(); - // check if new bidder already has an outbidded amount for the username(still in the contract) - // let bidder_amount = self.order_return.entry(bidder).entry(username).read(); - // self.order_return.entry(bidder).entry(username).write(0); - - // if amount > bidder_amount { - // if self.is_payment_enabled.read() { - // let payment_token = IERC20Dispatcher { contract_address: quote_token }; - // payment_token.transfer_from(bidder, get_contract_address(), (amount - bidder_amount)); - // } - // } - let payment_token = IERC20Dispatcher { contract_address: self.token_quote.read() }; payment_token.transfer_from(bidder, get_contract_address(), amount); let order_id = self.order_count.entry(username).read() + 1_u256; let new_order = Order { id: order_id, bidder: bidder, amount: amount, is_active: true }; - // let old_order = self.orders.read(username); - // Store the order self.orders.entry((username, order_id)).write(new_order); self.order_count.entry(username).write(order_id); From 81370ec4fb8431492b87e1b401bd7f12daa5d59b Mon Sep 17 00:00:00 2001 From: Hakeem Kazeem Date: Sat, 30 Nov 2024 15:27:26 +0100 Subject: [PATCH 9/9] is_accepted_price_reached removed --- onchain/cairo/src/afk_id/nameservice.cairo | 11 ----------- .../cairo/src/interfaces/nameservice.cairo | 1 - .../cairo/src/tests/nameservice_tests.cairo | 19 +++++++++---------- 3 files changed, 9 insertions(+), 22 deletions(-) diff --git a/onchain/cairo/src/afk_id/nameservice.cairo b/onchain/cairo/src/afk_id/nameservice.cairo index cd52055b..26027fd0 100644 --- a/onchain/cairo/src/afk_id/nameservice.cairo +++ b/onchain/cairo/src/afk_id/nameservice.cairo @@ -105,7 +105,6 @@ pub mod Nameservice { pub struct Auction { pub owner: ContractAddress, pub minimal_price: u256, - pub is_accepted_price_reached: bool, pub highest_bid: u256, pub highest_bidder: ContractAddress, } @@ -211,7 +210,6 @@ pub mod Nameservice { owner: ContractAddress, username: felt252, minimal_price: u256, - is_accepted_price_reached: bool } @@ -364,7 +362,6 @@ pub mod Nameservice { ref self: ContractState, username: felt252, minimal_price: u256, - is_accepted_price_reached: bool ) { let caller_address = get_caller_address(); let username_address = self.get_username_address(username); @@ -385,7 +382,6 @@ pub mod Nameservice { let new_auction = Auction { owner: caller_address, minimal_price: minimal_price, - is_accepted_price_reached: is_accepted_price_reached, highest_bid: 0, highest_bidder: contract_address_const::<0>(), }; @@ -398,7 +394,6 @@ pub mod Nameservice { owner: caller_address, username: username, minimal_price, - is_accepted_price_reached } ); } @@ -429,7 +424,6 @@ pub mod Nameservice { let mut updated_auction = auction; updated_auction.highest_bid = amount; updated_auction.highest_bidder = bidder; - updated_auction.is_accepted_price_reached = false; self.auctions.write(username, updated_auction); } @@ -440,7 +434,6 @@ pub mod Nameservice { let auction = self.auctions.read(username); assert(auction.owner == caller, UserNameClaimErrors::USER_NOT_AUCTION_OWNER); - assert(auction.is_accepted_price_reached == false, UserNameClaimErrors::ACCEPTED_PRICE_REACHED); let order = self.orders.entry((username, id)).read(); assert(order.is_active == true, UserNameClaimErrors::ORDER_INACTIVE); @@ -452,10 +445,7 @@ pub mod Nameservice { updated_order.is_active = false; self.orders.entry((username, id)).write(order); - // Update auction is_accepted_price_reached let mut updated_auction = auction; - updated_auction.is_accepted_price_reached = true; - self.auctions.write(username, updated_auction); // Send token from contract to auction owner let token = IERC20Dispatcher { contract_address: self.token_quote.read() }; @@ -492,7 +482,6 @@ pub mod Nameservice { let mut updated_auction = auction; updated_auction.highest_bid = 0; updated_auction.highest_bidder = contract_address_const::<0>(); - updated_auction.is_accepted_price_reached = false; self.auctions.write(username, updated_auction); let token = IERC20Dispatcher { contract_address: self.token_quote.read() }; diff --git a/onchain/cairo/src/interfaces/nameservice.cairo b/onchain/cairo/src/interfaces/nameservice.cairo index 995e312f..dd268e1e 100644 --- a/onchain/cairo/src/interfaces/nameservice.cairo +++ b/onchain/cairo/src/interfaces/nameservice.cairo @@ -10,7 +10,6 @@ pub trait INameservice { ref self: TContractState, username: felt252, minimal_price: u256, - is_accepted_price_reached: bool ); fn place_order(ref self: TContractState, username: felt252, amount: u256); fn cancel_order(ref self: TContractState, username: felt252, id: u64); diff --git a/onchain/cairo/src/tests/nameservice_tests.cairo b/onchain/cairo/src/tests/nameservice_tests.cairo index ea229352..05f968c8 100644 --- a/onchain/cairo/src/tests/nameservice_tests.cairo +++ b/onchain/cairo/src/tests/nameservice_tests.cairo @@ -280,12 +280,11 @@ mod nameservice_tests { let username = selector!("test"); start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); nameservice_dispatcher.claim_username(username); - nameservice_dispatcher.create_auction_for_username(username, 100_u256, false); + nameservice_dispatcher.create_auction_for_username(username, 100_u256); stop_cheat_caller_address(nameservice_dispatcher.contract_address); let existing_auction = nameservice_dispatcher.get_auction(username); assert(existing_auction.minimal_price == 100, 'Minimal price not correct'); - assert(existing_auction.is_accepted_price_reached == false, 'price not correct'); assert(existing_auction.highest_bid == 0, 'highest_bid not correct'); assert(existing_auction.highest_bidder == starknet::contract_address_const::<0>(), 'highest_bidder not correct'); } @@ -313,7 +312,7 @@ mod nameservice_tests { let username = selector!("test"); start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); - nameservice_dispatcher.create_auction_for_username(username, 100_u256, false); + nameservice_dispatcher.create_auction_for_username(username, 100_u256); stop_cheat_caller_address(nameservice_dispatcher.contract_address); } @@ -346,7 +345,7 @@ mod nameservice_tests { stop_cheat_caller_address(nameservice_dispatcher.contract_address); start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); - nameservice_dispatcher.create_auction_for_username(username, 5_u256, false); + nameservice_dispatcher.create_auction_for_username(username, 5_u256); stop_cheat_caller_address(nameservice_dispatcher.contract_address); start_cheat_caller_address(payment_token_dispatcher.contract_address, NEW_CALLER()); @@ -400,7 +399,7 @@ mod nameservice_tests { stop_cheat_caller_address(nameservice_dispatcher.contract_address); start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); //10 - nameservice_dispatcher.create_auction_for_username(username, 5_u256, false); + nameservice_dispatcher.create_auction_for_username(username, 5_u256); stop_cheat_caller_address(nameservice_dispatcher.contract_address); start_cheat_caller_address(payment_token_dispatcher.contract_address, NEW_CALLER()); //2 @@ -462,7 +461,7 @@ mod nameservice_tests { stop_cheat_caller_address(nameservice_dispatcher.contract_address); start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); - nameservice_dispatcher.create_auction_for_username(username, 5_u256, false); + nameservice_dispatcher.create_auction_for_username(username, 5_u256); stop_cheat_caller_address(nameservice_dispatcher.contract_address); start_cheat_caller_address(payment_token_dispatcher.contract_address, NEW_CALLER()); @@ -509,7 +508,7 @@ mod nameservice_tests { stop_cheat_caller_address(nameservice_dispatcher.contract_address); start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); //10 - nameservice_dispatcher.create_auction_for_username(username, 5_u256, false); + nameservice_dispatcher.create_auction_for_username(username, 5_u256); stop_cheat_caller_address(nameservice_dispatcher.contract_address); start_cheat_caller_address(payment_token_dispatcher.contract_address, NEW_CALLER()); //2 @@ -577,7 +576,7 @@ mod nameservice_tests { assert(stored_address == CALLER(), 'Address not set'); start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); //10 - nameservice_dispatcher.create_auction_for_username(username, 5_u256, false); + nameservice_dispatcher.create_auction_for_username(username, 5_u256); stop_cheat_caller_address(nameservice_dispatcher.contract_address); start_cheat_caller_address(payment_token_dispatcher.contract_address, NEW_CALLER()); //2 @@ -642,7 +641,7 @@ mod nameservice_tests { assert(stored_address == CALLER(), 'Address not set'); start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); //10 - nameservice_dispatcher.create_auction_for_username(username, 5_u256, false); + nameservice_dispatcher.create_auction_for_username(username, 5_u256); stop_cheat_caller_address(nameservice_dispatcher.contract_address); start_cheat_caller_address(payment_token_dispatcher.contract_address, NEW_CALLER()); //2 @@ -720,7 +719,7 @@ mod nameservice_tests { assert(stored_address == CALLER(), 'Address not set'); start_cheat_caller_address(nameservice_dispatcher.contract_address, CALLER()); //10 - nameservice_dispatcher.create_auction_for_username(username, 5_u256, false); + nameservice_dispatcher.create_auction_for_username(username, 5_u256); stop_cheat_caller_address(nameservice_dispatcher.contract_address); start_cheat_caller_address(payment_token_dispatcher.contract_address, NEW_CALLER()); //2