From f5958b4861e02eacf0a580bd0b5cf49aef24b589 Mon Sep 17 00:00:00 2001 From: MSGhais Date: Mon, 10 Feb 2025 16:52:49 +0700 Subject: [PATCH 1/4] improve ui and start setup local dev docker WIP --- Dockerfile | 27 ++++++++++ apps/data-backend/.env.example | 4 +- apps/data-backend/src/index.ts | 13 +++-- apps/mobile/src/screens/Games/index.tsx | 4 +- apps/mobile/src/types/tab.ts | 66 +++++++++++++++++++++++++ docker-compose.yml | 66 +++++++++++++++++++++++++ 6 files changed, 172 insertions(+), 8 deletions(-) create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..b220b93d8 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,27 @@ +# Use a Node.js base image +FROM node:20 + +# Set the working directory +WORKDIR /app + +# Copy package.json and pnpm-lock.yaml +COPY package.json pnpm-lock.yaml ./ + +# Install pnpm +RUN npm install -g pnpm + +# Install dependencies +RUN pnpm install + +# Copy the rest of the application code +COPY . . + +# Build the application +ARG APP_PATH +RUN pnpm run build --filter=${APP_PATH} + +# Expose the port the app runs on +EXPOSE 3000 + +# Start the application +CMD ["pnpm", "run", "start"] \ No newline at end of file diff --git a/apps/data-backend/.env.example b/apps/data-backend/.env.example index 5e95b13be..036814ae0 100644 --- a/apps/data-backend/.env.example +++ b/apps/data-backend/.env.example @@ -1,3 +1,5 @@ +NODE_ENV="development" + TELEGRAM_WEB_APP="https://tg.afk-community.xyz" INDEXER_DATABASE_URL="postgresql://postgres:postgres@localhost:5434/indexer" @@ -28,7 +30,7 @@ STARKNET_RPC_NETWORK="SN_SEPOLIA" # SN_SEPOLIA, SN_MAIN RPC_NODE_API_KEY="" SN_NETWORK="SN_SEPOLIA" - +IS_TELEGRAM_BOT_RUNNING="false" # Cloudfare CLOUDFARE_ACCOUNT_ID="" CLOUDFARE_AUTH_TOKEN="" diff --git a/apps/data-backend/src/index.ts b/apps/data-backend/src/index.ts index d9634e168..0a661bf59 100644 --- a/apps/data-backend/src/index.ts +++ b/apps/data-backend/src/index.ts @@ -114,11 +114,14 @@ async function start() { console.log(`Server listening on ${host}:${config.server.port}`); // Launch Telegram bot - try { - await launchBot(process.env.TELEGRAM_BOT_TOKEN || ''); - } catch (error) { - console.error('Error launching bot:', error); - } + + if (process.env.TELEGRAM_BOT_TOKEN && process.env.IS_TELEGRAM_BOT_RUNNING === 'true') { + try { + await launchBot(process.env.TELEGRAM_BOT_TOKEN || ''); + } catch (error) { + console.log('Error launching bot:', error); + } + } } catch (err) { console.error(err); process.exit(1); diff --git a/apps/mobile/src/screens/Games/index.tsx b/apps/mobile/src/screens/Games/index.tsx index fc88e98b0..402716a78 100644 --- a/apps/mobile/src/screens/Games/index.tsx +++ b/apps/mobile/src/screens/Games/index.tsx @@ -5,7 +5,7 @@ import {SafeAreaView} from 'react-native-safe-area-context'; import {useStyles, useTheme, useWindowDimensions} from '../../hooks'; import {PixelPeace} from '../../modules/PixelPeace'; import {GameSreenProps} from '../../types'; -import {SelectedTab, TABS_MENU} from '../../types/tab'; +import {SelectedTab, CONSOLE_TABS_MENU} from '../../types/tab'; import {AllKeysComponent} from '../KeysMarketplace/AllKeysComponent'; import {LaunchpadComponent} from '../Launchpad/LaunchpadComponent'; import {SlinksMap} from '../Slink/SlinksMap'; @@ -44,7 +44,7 @@ export const Games: React.FC = ({navigation}) => { ]} showsVerticalScrollIndicator={false} > - {TABS_MENU.map((option) => ( + {CONSOLE_TABS_MENU.map((option) => ( handleTabSelected(option.tab)} diff --git a/apps/mobile/src/types/tab.ts b/apps/mobile/src/types/tab.ts index 9a329fc99..105363e97 100644 --- a/apps/mobile/src/types/tab.ts +++ b/apps/mobile/src/types/tab.ts @@ -511,5 +511,71 @@ export const TABS_COMMUNITY: {screen?: string; title: string; tab: SelectedTab}[ // screen: "ChannelsFeed", // tab: SelectedTab.MESSAGES + // }, +]; + +export const CONSOLE_TABS_MENU: {screen?: string; title: string; description: string; tab: SelectedTab}[] = [ + { + title: 'Pump', + description: 'Launch your token to be trade and pumped', + screen: 'Launchpad', + tab: SelectedTab.LAUNCHPAD_VIEW, + }, + { + title: 'Pixel Peace', + description: 'Pixel Game for communities', + screen: 'PixelPeace', + tab: SelectedTab.PIXEL_PEACE, + }, + { + title: 'Nameservice', + description: 'AFK nameservice to mint your own name.afk', + screen: 'AFK Nameservice', + tab: SelectedTab.NAMESERVICE, + }, + // { + // title: 'AFK ID', + // screen: 'AFK ID', + // tab: SelectedTab.AFK_ID, + // }, + { + title: 'Keys', + description: 'Launch your own keys as a Starknet user linked to your profile', + screen: 'KeysMarketplace', + tab: SelectedTab.VIEW_KEYS_MARKETPLACE, + }, + // { + // title: 'Slink', + // description: 'Slink Description', + // screen: 'Slink', + // tab: SelectedTab.SLINK, + // }, + // { + // title: '?', + // description: '? Description', + // screen: '?', + // tab: SelectedTab.LAUNCH_TOKEN_UNRUGGABLE, + // }, + // { + // title: '?!', + // description: '?! Description', + // screen: '?!', + // tab: SelectedTab.LAUNCH_TOKEN_PUMP, + // }, + // { + // title: 'Channel', + // screen: 'CreateChannel', + // tab: SelectedTab.CREATE_CHANNEL, + // }, + // { + // title: 'Token', + // screen: 'LaunchToken', + // tab: SelectedTab.LAUNCH_TOKEN, + // }, + // { + // title: 'Messages', + // screen: "ChannelsFeed", + // tab: SelectedTab.MESSAGES + // }, ]; \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..5b19c3e54 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,66 @@ +version: '3.8' + +services: + mobile: + build: + context: . + dockerfile: Dockerfile + args: + APP_PATH: apps/mobile + working_dir: /app/apps/mobile + command: pnpm run start + volumes: + - .:/app + ports: + - "${MOBILE_PORT}:${MOBILE_PORT}" # Use environment variable + depends_on: + - packages + env_file: + - .env + + data-backend: + build: + context: . + dockerfile: Dockerfile + args: + APP_PATH: apps/data-backend + working_dir: /app/apps/data-backend + command: pnpm run start + volumes: + - .:/app + ports: + - "${DATA_BACKEND_PORT}:${DATA_BACKEND_PORT}" # Use environment variable + depends_on: + - packages + env_file: + - .env + + nestjs-indexer: + build: + context: . + dockerfile: Dockerfile + args: + APP_PATH: apps/nestjs-indexer + working_dir: /app/apps/nestjs-indexer + command: pnpm run start + volumes: + - .:/app + ports: + - "${NESTJS_INDEXER_PORT}:${NESTJS_INDEXER_PORT}" # Use environment variable + depends_on: + - packages + env_file: + - .env + + packages: + build: + context: . + dockerfile: Dockerfile + args: + APP_PATH: packages + working_dir: /app/packages + command: pnpm run build + volumes: + - .:/app + env_file: + - .env \ No newline at end of file From 0010f2327dd2be1042ada06bf0fd004f47eaded5 Mon Sep 17 00:00:00 2001 From: MSGhais Date: Mon, 10 Feb 2025 23:41:34 +0700 Subject: [PATCH 2/4] add comment and last clean of launchpad.cairo --- .../launchpad/src/launchpad/launchpad.cairo | 122 +++++++++++------- 1 file changed, 77 insertions(+), 45 deletions(-) diff --git a/onchain/cairo/launchpad/src/launchpad/launchpad.cairo b/onchain/cairo/launchpad/src/launchpad/launchpad.cairo index b752849e7..e501e5147 100644 --- a/onchain/cairo/launchpad/src/launchpad/launchpad.cairo +++ b/onchain/cairo/launchpad/src/launchpad/launchpad.cairo @@ -77,12 +77,12 @@ pub mod LaunchpadMarketplace { const MAX_SUPPLY: u256 = 100_000_000; const INITIAL_SUPPLY: u256 = MAX_SUPPLY / 5; - const MAX_STEPS_LOOP: u256 = 100; // TODO add optional parameters to be select LIQ percent to be lock to Unrug at some point // 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 @@ -92,6 +92,7 @@ pub mod LaunchpadMarketplace { const MID_FEE_PROTOCOL: u256 = 100; //1% const SLIPPAGE_THRESHOLD: u256 = 100; //1% + // TODO Used in V2 and be choose by user const MIN_FEE_CREATOR: u256 = 100; //1% const MID_FEE_CREATOR: u256 = 1000; //10% const MAX_FEE_CREATOR: u256 = 5000; //50% @@ -100,33 +101,19 @@ pub mod LaunchpadMarketplace { const SCALE_FACTOR: u256 = 100_000_000_000_000_000_u256; // Scale factor decimals place for price division and others stuff - // MVP + // MVP TODO AUDIT FLEXIBLE SUPPLY with Fuzzing // FIXED SUPPLY because edge cases not finish testing hard between threshold/supply const FIXED_SUPPLY: u256 = 1_000_000_000_000_000_000_000_000_000_u256; // 1_000_000_000 // 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; - const DEFAULT_MIN_LOCKTIME: u64 = 15_721_200; // const MAX_TRANSACTION_AMOUNT: u256 = 1_000_000 * pow_256(10, 18); - // fn _validate_transaction_size(amount: u256) { // assert(amount <= MAX_TRANSACTION_AMOUNT, 'transaction too large'); // } - component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent); component!(path: SRC5Component, storage: src5, event: SRC5Event); - // AccessControl #[abi(embed_v0)] impl AccessControlImpl = @@ -282,6 +269,9 @@ pub mod LaunchpadMarketplace { // self.is_fees_protocol_buy_enabled.write(false); // self.is_fees_protocol_sell_enabled.write(false); + // TODO AUDIT + // Check fees implementation in buy an sell + // Rounding and approximation can caused an issue self.is_fees_protocol_buy_enabled.write(true); self.is_fees_protocol_sell_enabled.write(true); self.is_fees_protocol_enabled.write(true); @@ -306,6 +296,7 @@ pub mod LaunchpadMarketplace { is_enable: true, step_increase_linear }; + // TODO test add case if the payment are needed to create and launch self.is_custom_launch_enable.write(false); self.is_custom_token_enable.write(false); self.default_token.write(init_token.clone()); @@ -319,6 +310,7 @@ pub mod LaunchpadMarketplace { self.total_launch.write(0); self.protocol_fee_percent.write(MID_FEE_PROTOCOL); self.creator_fee_percent.write(MIN_FEE_CREATOR); + // Unrug Liquitidy to deposit through Ekubo self.unrug_liquidity_address.write(unrug_liquidity_address); } @@ -514,7 +506,9 @@ pub mod LaunchpadMarketplace { // User call // Create token for an user - // Send the supply to the caller + // Send the supply to the recipient + // Add Ownable to the caller + // Add Factory address for the memecoin.cairo fn create_token( ref self: ContractState, recipient: ContractAddress, @@ -543,6 +537,9 @@ pub mod LaunchpadMarketplace { } // Create coin and launch in bonding curve + // Need to have the allowance of the total supply to be used + // 80% percent on sale and 20% for the Liquidity pool when bonding curve reached threshold + // Threshold is setup by the admin and save in the pool struct (in case we change) fn create_and_launch_token( ref self: ContractState, symbol: ByteArray, @@ -573,6 +570,9 @@ pub mod LaunchpadMarketplace { } // Launch coin to pool bonding curve + // Need to have the allowance of the total supply to be used + // 80% percent on sale and 20% for the Liquidity pool when bonding curve reached threshold + // Threshold is setup by the admin and save in the pool struct (in case we change) fn launch_token( ref self: ContractState, coin_address: ContractAddress, bonding_type: BondingType ) { @@ -609,6 +609,11 @@ pub mod LaunchpadMarketplace { let protocol_fee_percent = self.protocol_fee_percent.read(); let mut amount_protocol_fee = 0; let mut remain_quote_to_liquidity = quote_amount; + + // HIGH SECURITY RISK For Liquidity Ekubo and Buy coin + // Calculate threshold before launch the liquidity + // We add a slippage tolerance to launch on the threshold and thresloss - 2% + // We also substract protocol fees to the threshold: MAYBE CAUSING ISSUE let mut threshold_liquidity = pool.threshold_liquidity.clone(); let mut slippage_threshold: u256 = threshold_liquidity * SLIPPAGE_THRESHOLD / BPS; @@ -616,8 +621,9 @@ pub mod LaunchpadMarketplace { let mut threshold = threshold_liquidity - slippage_threshold; // Substract fees protocol from threshold and the quote amount to used to calculate the // coin amount Handle protocol fees if enabled - // HIGH SECURITY ISSUE + // HIGH SECURITY RISK ISSUE // Security check to do + // Rounding and approximation of the percentage can lead to security vulnerabilities if self.is_fees_protocol_enabled.read() && self.is_fees_protocol_buy_enabled.read() { amount_protocol_fee = quote_amount * protocol_fee_percent / BPS; remain_quote_to_liquidity = quote_amount - amount_protocol_fee; @@ -634,9 +640,12 @@ pub mod LaunchpadMarketplace { let new_liquidity = pool.liquidity_raised + remain_quote_to_liquidity; // assert(new_liquidity <= threshold_liquidity, errors::THRESHOLD_LIQUIDITY_EXCEEDED); + // TODO V2 + // add the Creator feed here setup by the user + // Calculate coin amount to receive // AUDIT - // High security check to do. + // High security risk. // Verify rounding issue and approximation of the quote amount caused overflow let coin_amount = get_amount_by_type_of_coin_or_quote( pool.clone(), coin_address, remain_quote_to_liquidity, false, true @@ -655,7 +664,6 @@ pub mod LaunchpadMarketplace { pool.price = quote_amount; pool.total_token_holded += coin_amount; - // pool.available_supply -= coin_amount; if coin_amount >= pool.available_supply { pool.available_supply = 0; pool.total_token_holded += coin_amount; @@ -688,8 +696,14 @@ pub mod LaunchpadMarketplace { // Check if liquidity threshold reached // let threshold = pool.threshold_liquidity - (pool.threshold_liquidity * // SLIPPAGE_THRESHOLD / BPS); + // Update pool first time + // Used by the add liquidity ekubo, + // maybe better to only sent the mut storage to the function to not write two times the state self.launched_coins.entry(coin_address).write(pool); + // High security risk + // Launch to ekubo if the liquidity raised = threshold liquidity + // This threshold liquidity have a slippage tolrance of 2% and less protocl fees if pool.liquidity_raised >= threshold { self .emit( @@ -700,7 +714,7 @@ pub mod LaunchpadMarketplace { } ); - // Add liquidity to DEX + // Add liquidity to DEX Ekubo self._add_liquidity_ekubo(coin_address); pool.is_liquidity_launch = true; } @@ -743,7 +757,7 @@ pub mod LaunchpadMarketplace { // Get user's share and validate amount let mut share = self.shares_by_users.entry(caller).entry(coin_address).read(); - // Adjust sell amount if needed + // Adjust sell amount if needed to the max owne by user if it's above it let mut sell_amount = if share.amount_owned < coin_amount { share.amount_owned } else { @@ -753,7 +767,9 @@ pub mod LaunchpadMarketplace { assert(share.amount_owned >= sell_amount, errors::ABOVE_SUPPLY); // Calculate fees + // Get percentage fees setup for protoocol let protocol_fee_percent = self.protocol_fee_percent.read(); + // TODO V2: used creator fees setup by admin/user let creator_fee_percent = self.creator_fee_percent.read(); assert( protocol_fee_percent <= MAX_FEE_PROTOCOL @@ -764,13 +780,17 @@ pub mod LaunchpadMarketplace { // share.amount_owned <= pool.total_token_holded, // errors::SUPPLY_ABOVE_TOTAL_OWNED // ); - // Calculate quote token amounts + // Calculate quote token amounts to received with the amount of memecoin sell let mut quote_amount_total = get_amount_by_type_of_coin_or_quote( pool.clone(), coin_address, sell_amount, true, false ); let mut quote_amount = quote_amount_total.clone(); - // println!("quote_amount_total first: {}", quote_amount_total.clone()); + // AUDIT + // HIGH RISK SECURITY + // Rounding and approximation of the Linear and Exponential bonding curve can occurs + // Calculate fees for protocol based on this quote amount calculated + // let protocol_fee_amount = quote_amount * protocol_fee_percent / BPS; let creator_fee_amount = quote_amount * creator_fee_percent / BPS; @@ -792,10 +812,11 @@ pub mod LaunchpadMarketplace { quote_amount -= quote_fee_amount; } - // Validate against liquidity and balance constraints // AUDIT + // Validate against liquidity and balance constraints // High security check to do. // Approximation and rounding issue can cause to enter this check + // We maybe do something wrong to enter this check // println!("check liq raised and quote amount"); if pool.liquidity_raised < quote_amount { // println!("pool.liquidity_raised < quote_amount"); @@ -833,29 +854,22 @@ pub mod LaunchpadMarketplace { // Security check to do. // Rounding issue and approximation of the quote amount caused overflow/underflow when // transfering the token to the user - if balance_contract > quote_amount_paid { + // We do something wrong to enter this check + if balance_contract >= quote_amount_paid { quote_token.transfer(caller, quote_amount_paid); } else { + + // Balance doesn't have the quote amount to paid + // AUDIT HIGH SECURITY + // Rounding and approximation on calculation and fees have lost some precision // let quote_amount_paid = quote_amount - quote_fee_amount; let difference_amount = quote_amount_paid - balance_contract; let amount_paid = quote_amount_paid - difference_amount; // println!("amount_paid: {}", amount_paid.clone()); quote_token.transfer(caller, amount_paid); } - // if balance_contract > quote_amount { - // quote_token.transfer(caller, quote_amount); - // } else { - // let amount_paid= quote_amount - balance_contract; - // println!("amount_paid: {}", amount_paid.clone()); - // quote_token.transfer(caller, amount_paid); - // } - // if quote_amount > 0 { - // quote_token.transfer(caller, quote_amount); - // } - - // Update state - // println!("update share"); + // Update state of share user share.amount_owned -= sell_amount; share.amount_sell += sell_amount; @@ -863,6 +877,8 @@ pub mod LaunchpadMarketplace { let mut updated_pool = pool.clone(); // println!("update pool"); + // Update the pool with the last data + // Liquidity raised, available supply and total token holded updated_pool .liquidity_raised = if updated_pool.liquidity_raised >= quote_amount { @@ -972,7 +988,7 @@ pub mod LaunchpadMarketplace { } ); } - // TODO finish add Metadata + // TODO finish add Metadata for Token and Launched and also updated it fn add_metadata( ref self: ContractState, coin_address: ContractAddress, metadata: MetadataLaunch ) { @@ -1006,7 +1022,8 @@ pub mod LaunchpadMarketplace { pool.clone(), coin_address, amount, is_decreased, is_quote_amount ) } - + // Get the amount of coin received by quote amount + // Bonding curve calculation are Linear and Exponential fn get_coin_amount_by_quote_amount( self: @ContractState, coin_address: ContractAddress, @@ -1052,6 +1069,7 @@ pub mod LaunchpadMarketplace { let caller = get_caller_address(); // TODO finish this + // ADD TEST CASE for Paid create token let is_paid_create_token_enable = self.is_paid_create_token_enable.read(); if is_paid_create_token_enable { let token_address_to_paid_create_token = self @@ -1126,6 +1144,7 @@ pub mod LaunchpadMarketplace { let caller = get_caller_address(); let token = self.token_created.read(coin_address); + // TODO Add test for Paid launched token bonding curve // Handle paid launch if enabled // Price of the token and the address is set by the admin if self.is_paid_launch_enable.read() { @@ -1154,6 +1173,8 @@ pub mod LaunchpadMarketplace { // Calculate supply distribution // AUDIT: check rounding and approximation issue // V2 is gonna be more flexible here for the user + // V2 allow you to select your token on sale between a range to figure out + // a range of liquidity to add (5 to 25%) let liquidity_supply = total_supply / LIQUIDITY_RATIO; let supply_distribution = total_supply - liquidity_supply; @@ -1181,6 +1202,9 @@ pub mod LaunchpadMarketplace { creator_fee_percent: self.creator_fee_percent.read() }; + + // TODO Check approve + // AUDIT // Handle token transfer to the launchpad // Check the allowance and the balance of the contract // The user need to approve the token to the launchpad if the token is created elsewhere @@ -1218,10 +1242,14 @@ pub mod LaunchpadMarketplace { ); } - // Call the Unrug V2 to deposit Liquidity of the memecoin initial_pool_supply and the - // liquidity_raised The LP is owned by the Launchpad and locked it + // TODO AUDIT: check rounding and approximation issue // HIGH SECURITY RISK and Vulnerability + // ADD more test case for Unrug + // Check better the liquidity position of Ekubo + // Call the Unrug V2 to deposit Liquidity of the memecoin initial_pool_supply and the + // liquidity_raised The LP is owned by the Launchpad and locked it + fn _add_liquidity_ekubo( ref self: ContractState, coin_address: ContractAddress, ) -> (u64, EkuboLP) { @@ -1243,7 +1271,8 @@ pub mod LaunchpadMarketplace { // Set pool parameters // TODO audit // HIGH SECURITY RISK - // V2 need to be more flexible here for the user + // V2 need to be more flexible here for the user. + // Add more test case let tick_spacing = 5928; let bound_spacing = tick_spacing * 2; let pool_params = EkuboPoolParameters { @@ -1256,6 +1285,7 @@ pub mod LaunchpadMarketplace { }; // Calculate liquidity amounts + // AUDIT let lp_supply = launch.initial_pool_supply.clone(); let mut lp_quote_supply = launch.liquidity_raised.clone(); @@ -1267,8 +1297,9 @@ pub mod LaunchpadMarketplace { // TODO audit // HIGH SECURITY RISK - // Can be a rounding and approximation error, fees and others stuff // TODO fix this + // We do something wrong if we enter this case + // Can be caused a rounding and approximation error, fees and others stuff if contract_quote_balance < lp_quote_supply && contract_quote_balance < launch.threshold_liquidity { lp_quote_supply = contract_quote_balance.clone(); @@ -1291,6 +1322,7 @@ pub mod LaunchpadMarketplace { memecoin.approve(unrug_liquidity_address, lp_supply); // Launch on Ekubo + // TODO Audit unrug.caior let (id, position) = unrug_liquidity.launch_on_ekubo(coin_address, params); // Update launch state From 0880ac236752a90705e92d9a131a6ea2c7e4ddb9 Mon Sep 17 00:00:00 2001 From: MSGhais Date: Mon, 10 Feb 2025 23:43:46 +0700 Subject: [PATCH 3/4] fmt --- .../launchpad/src/launchpad/launchpad.cairo | 17 ++++++++--------- .../cairo/launchpad/src/types/keys_types.cairo | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/onchain/cairo/launchpad/src/launchpad/launchpad.cairo b/onchain/cairo/launchpad/src/launchpad/launchpad.cairo index e501e5147..6e4daac24 100644 --- a/onchain/cairo/launchpad/src/launchpad/launchpad.cairo +++ b/onchain/cairo/launchpad/src/launchpad/launchpad.cairo @@ -269,7 +269,7 @@ pub mod LaunchpadMarketplace { // self.is_fees_protocol_buy_enabled.write(false); // self.is_fees_protocol_sell_enabled.write(false); - // TODO AUDIT + // TODO AUDIT // Check fees implementation in buy an sell // Rounding and approximation can caused an issue self.is_fees_protocol_buy_enabled.write(true); @@ -697,8 +697,9 @@ pub mod LaunchpadMarketplace { // let threshold = pool.threshold_liquidity - (pool.threshold_liquidity * // SLIPPAGE_THRESHOLD / BPS); // Update pool first time - // Used by the add liquidity ekubo, - // maybe better to only sent the mut storage to the function to not write two times the state + // Used by the add liquidity ekubo, + // maybe better to only sent the mut storage to the function to not write two times the + // state self.launched_coins.entry(coin_address).write(pool); // High security risk @@ -790,7 +791,7 @@ pub mod LaunchpadMarketplace { // HIGH RISK SECURITY // Rounding and approximation of the Linear and Exponential bonding curve can occurs // Calculate fees for protocol based on this quote amount calculated - // + // let protocol_fee_amount = quote_amount * protocol_fee_percent / BPS; let creator_fee_amount = quote_amount * creator_fee_percent / BPS; @@ -858,7 +859,6 @@ pub mod LaunchpadMarketplace { if balance_contract >= quote_amount_paid { quote_token.transfer(caller, quote_amount_paid); } else { - // Balance doesn't have the quote amount to paid // AUDIT HIGH SECURITY // Rounding and approximation on calculation and fees have lost some precision @@ -1022,7 +1022,7 @@ pub mod LaunchpadMarketplace { pool.clone(), coin_address, amount, is_decreased, is_quote_amount ) } - // Get the amount of coin received by quote amount + // Get the amount of coin received by quote amount // Bonding curve calculation are Linear and Exponential fn get_coin_amount_by_quote_amount( self: @ContractState, @@ -1202,7 +1202,6 @@ pub mod LaunchpadMarketplace { creator_fee_percent: self.creator_fee_percent.read() }; - // TODO Check approve // AUDIT // Handle token transfer to the launchpad @@ -1249,7 +1248,7 @@ pub mod LaunchpadMarketplace { // Check better the liquidity position of Ekubo // Call the Unrug V2 to deposit Liquidity of the memecoin initial_pool_supply and the // liquidity_raised The LP is owned by the Launchpad and locked it - + fn _add_liquidity_ekubo( ref self: ContractState, coin_address: ContractAddress, ) -> (u64, EkuboLP) { @@ -1285,7 +1284,7 @@ pub mod LaunchpadMarketplace { }; // Calculate liquidity amounts - // AUDIT + // AUDIT let lp_supply = launch.initial_pool_supply.clone(); let mut lp_quote_supply = launch.liquidity_raised.clone(); diff --git a/onchain/cairo/launchpad/src/types/keys_types.cairo b/onchain/cairo/launchpad/src/types/keys_types.cairo index 700531835..d36ef89e4 100644 --- a/onchain/cairo/launchpad/src/types/keys_types.cairo +++ b/onchain/cairo/launchpad/src/types/keys_types.cairo @@ -118,7 +118,7 @@ pub fn get_current_price(key: @Keys, supply: u256, amount_to_buy: u256) -> u256 pub fn get_linear_price( // key: @Keys, - key: Keys, supply: u256, // amount_to_buy: u256 +key: Keys, supply: u256, // amount_to_buy: u256 ) -> u256 { let step_increase_linear = key.token_quote.step_increase_linear.clone(); let initial_key_price = key.token_quote.initial_key_price.clone(); From 7b96c7cb4c813162d1b3e205048aff79bf2c63d9 Mon Sep 17 00:00:00 2001 From: MSGhais Date: Tue, 11 Feb 2025 03:27:08 +0700 Subject: [PATCH 4/4] add doc launchpad.md and comment --- onchain/cairo/launchpad/docs/launchpad.md | 204 +++++++++++++++++- onchain/cairo/launchpad/docs/nostr/deposit.md | 17 -- .../cairo/launchpad/docs/nostr/namespace.md | 11 - .../src/launchpad/calcul/exponential.cairo | 72 ++++++- .../src/launchpad/calcul/launch.cairo | 1 - .../src/launchpad/calcul/linear.cairo | 62 +++++- 6 files changed, 324 insertions(+), 43 deletions(-) delete mode 100644 onchain/cairo/launchpad/docs/nostr/deposit.md delete mode 100644 onchain/cairo/launchpad/docs/nostr/namespace.md diff --git a/onchain/cairo/launchpad/docs/launchpad.md b/onchain/cairo/launchpad/docs/launchpad.md index 247569fb1..4026257d8 100644 --- a/onchain/cairo/launchpad/docs/launchpad.md +++ b/onchain/cairo/launchpad/docs/launchpad.md @@ -7,7 +7,7 @@ launch a bonding curve fair launch, or add liquidity safely and unruggable for y ## What you can do: - Create token with supply chosen etc -- Launch token bonding curve: in hard test +- Launch token bonding curve: Linear and Exponential - Add liquidity after bonding curve a. Ekubo (done) b. Jediswap (WIP) @@ -20,12 +20,208 @@ b. Jediswap (WIP) # Files scope launchpad.cairo : (WIP refacto into few components reusable) +launchpad_types.cairo calcul.cairo +linear.cairo +launch.cairo +exponential.cairo memecoin.cairo & memecoin_v2.cairo soon -# Specs +# Functionnalities Contract in launchpad.cairo -Bonding curve located in calcul.cairo +Bonding curve located in linear.cairo and exponential.cairo System call of memecoin.cairo, soon memecoin_v2.cairo (OZ, Vote). -Interaction with Ekubo, Jediswap \ No newline at end of file +Interaction with Ekubo, Jediswap + + +# Smart Contract Documentation for Auditors + +## Core Contracts Overview + +### 1. Launchpad.cairo +The main contract handling token launches and liquidity management. + +Key Components: +- Token creation +- Launch management +- Bonding curve management +- Buy and sell coin +- Fee handling system (protocol fee, V2 with creator fees) +- Access control for admin functions +- Integration with DEXs (Ekubo, Jediswap planned) +- Upgradeable contract pattern + +Critical Areas: +- Fee calculations and rounding +- Access control for privileged functions +- State management during launches +- Token creation parameter validation +- Price calculations during buys/sells + +### 2. Linear.cairo +Implements linear bonding curve pricing mechanism. + +Key Functions: +- get_meme_amount(): Calculates tokens received when buying +- get_coin_amount(): Calculates quote tokens received when selling +- calculate_starting_price_launch(): Sets initial token price + +Critical Areas: +- Precision loss in calculations +- Overflow/underflow risks +- Edge cases in price calculations +- Scaling factors (SCALE_FACTOR, DECIMAL_FACTOR) +- Square root approximations + +### 3. Exponential.cairo +Implements exponential bonding curve using Taylor series approximation. + +Key Functions: +- exponential_approximation(): Calculates e^x using Taylor series +- logarithm_approximation(): Natural log approximation +- get_price(): Determines token price based on supply + +Critical Areas: +- Taylor series convergence and precision +- Term limit impact on accuracy +- Scaling factors for large numbers +- Gas costs with iteration +- Numerical stability + +## Security Considerations + +### Price Manipulation Risks +- Front-running opportunities during price changes +- Price impact on large trades +- Rounding errors accumulation +- Precision loss in math operations + +### State Management +- Race conditions during launches +- Reentrancy vulnerabilities +- Storage slot collisions +- Access control enforcement + +### Economic Security +- Fee calculation accuracy +- Liquidity pool manipulation +- Token supply management +- Price oracle dependencies + +### Integration Points +- DEX interaction safety +- External call handling +- Event emission consistency +- Upgrade mechanism security + +## Known Edge Cases + +1. Price Calculation +- Zero amount trades +- Max supply reached +- Minimum price thresholds +- Extreme price swings + +2. Liquidity Management +- Initial pool setup +- Emergency withdrawals +- Fee distribution +- Reserve ratio maintenance + +3. Token Operations +- Creation parameters +- Launch constraints +- Trading limitations +- Supply boundaries + +## Audit Focus Areas + +1. Mathematical Precision +- Verify bonding curve calculations +- Check rounding behavior +- Test boundary conditions +- Validate scaling factors + +2. Access Controls +- Admin role restrictions +- Function permissions +- Upgrade controls +- Emergency functions + +3. Economic Design +- Fee model sustainability +- Price manipulation resistance +- Liquidity incentives +- Market dynamics + +4. Integration Security +- DEX interaction safety +- External call handling +- Event consistency +- State synchronization + +5. Contract-Specific Security Considerations + +### Launchpad.cairo +Key Security Points: +- Token creation validation: Ensure parameters like supply, name, symbol are properly validated +- Fee handling: Check for precision loss in fee calculations and distributions +- State management: Verify atomic operations during launches and liquidity additions +- Access control: Review admin functions and role-based permissions +- Upgrade mechanism: Assess security of upgrade pattern and potential vulnerabilities + +Critical Functions: +- `create_token()`: Validates and initializes new token +- `create_token_and_launch()`: Validates and initializes new token launches and bonding curve +- `launch_token()`: Validates and initializes new token launches and bonding curve +- `buy_coin_by_quote()`: Handles token purchases via bonding curve +- `sell_coin()`: Processes token sales and quote token returns +- `_add_liquidity_ekubo()`: Manages DEX liquidity provision +- `claim_all()`: Claim all tokens after bonding curve reached +- `claim_friend()`: Claim friend for the friend tokens after bonding curve reached (automated claimed) + +### Linear.cairo +Bonding Curve Implementation: + +Key Security Considerations: +- Precision handling in slope/intercept calculations +- Overflow checks in price computations +- Edge cases: zero amounts, max supply +- Scaling factors for numerical stability +- Rounding behavior impact on pricing + +Critical Functions: +- `get_meme_amount()`: Calculates tokens received for quote token input +- `get_coin_amount()`: Calculates quote tokens received for token sales +- `calculate_starting_price_launch()`: Sets initial token price + +### Exponential.cairo +Bonding Curve Implementation: +- Uses exponential price function via Taylor series approximation +- Price increases exponentially with supply sold +- Configurable precision via TAYLOR_TERMS constant + +Key Security Considerations: +- Convergence of Taylor series approximation +- Precision loss in iterative calculations +- Gas costs for term computation +- Boundary conditions and extreme values +- Numerical stability at scale + +Critical Functions: +- `exponential_approximation()`: Core pricing calculation +- `logarithm_approximation()`: Inverse calculation for sales +- Term iteration and accumulation logic + +Common Vulnerabilities to Check: +1. Arithmetic overflow/underflow +2. Precision loss in calculations +3. Rounding errors accumulation +4. Gas limits in iterative functions +5. Front-running opportunities +6. Price manipulation vectors +7. State inconsistency scenarios +8. Reentrancy risks in external calls + + diff --git a/onchain/cairo/launchpad/docs/nostr/deposit.md b/onchain/cairo/launchpad/docs/nostr/deposit.md deleted file mode 100644 index 409a935ca..000000000 --- a/onchain/cairo/launchpad/docs/nostr/deposit.md +++ /dev/null @@ -1,17 +0,0 @@ -# Deposit Tips and Payment stream - -Deposit Escrow let you tips Nostr user directly with Starknet. - - -## What you can do: - -- Send a tip (without timelock) -- Send tips with timelock -- Claim your tips -- Claim tips without Gas (Gas fee get in the transaction, you just sign the Nostr event and a Backend paymaster paid it). Maybe security issue, and just use a Paymaster. -- Cancel your tips - -# Specs - -Verify Nostr event to claim your tips and verify your are the owner of the Nostr address -Linked your address with Nostr and Starknet (WIP Namespace get contract) diff --git a/onchain/cairo/launchpad/docs/nostr/namespace.md b/onchain/cairo/launchpad/docs/nostr/namespace.md deleted file mode 100644 index b5621ee83..000000000 --- a/onchain/cairo/launchpad/docs/nostr/namespace.md +++ /dev/null @@ -1,11 +0,0 @@ -# Namespace - -Linked a Nostr address to a Starknet address, and inversely. -Need a Nostr event signed to Verify on chain with BIP-340. - - -## What you can do: - -- Linked your Nostr address - -# Specs \ No newline at end of file diff --git a/onchain/cairo/launchpad/src/launchpad/calcul/exponential.cairo b/onchain/cairo/launchpad/src/launchpad/calcul/exponential.cairo index cc3975587..7225a1d39 100644 --- a/onchain/cairo/launchpad/src/launchpad/calcul/exponential.cairo +++ b/onchain/cairo/launchpad/src/launchpad/calcul/exponential.cairo @@ -11,6 +11,7 @@ const LN_2: u256 = 693_147_180_559_945_309_u256; // Exponential approximation // TODO Audit HIGH SECURITY // Rounding and approximation issue to check + pub fn exponential_approximation(x: u256, y: u256, terms: u256) -> u256 { if x == 0 { return DECIMAL_FACTOR; @@ -77,6 +78,46 @@ pub fn logarithm_approximation(x: u256, y: u256, terms: u256) -> u256 { // Logarithm approximation with a LOG_TERMS // TODO Audit HIGH SECURITY // Rounding and approximation issue to check +/// Logarithm Approximation Documentation for Auditors +/// +/// This function implements a logarithm approximation using Taylor series expansion +/// specifically optimized for values close to 1 (1+x). +/// +/// # Key Parameters +/// - x: Numerator of the fraction to compute ln(x/y) +/// - y: Denominator of the fraction +/// - terms: Number of Taylor series terms to use (affects precision) +/// +/// # Implementation Details +/// 1. Input Validation: +/// - Checks for zero input +/// - Handles cases where x > y by transforming calculation +/// +/// 2. Series Calculation: +/// - Alternates between adding and subtracting terms +/// - Uses scaled arithmetic (DECIMAL_FACTOR) for precision +/// - Early termination when terms become negligible +/// +/// 3. Special Cases: +/// - When x > y, combines with natural log calculation +/// - Maintains precision through scaled arithmetic +/// +/// # Security Considerations +/// - Precision loss in term calculations +/// - Convergence depends on input values +/// - Potential overflow in term multiplication +/// - Rounding errors in division +/// - Gas costs with iteration +/// - Edge cases: very small/large inputs +/// +/// # Known Limitations +/// - Precision decreases for inputs far from 1 +/// - Gas cost increases with more terms +/// - May not converge for certain input ranges +/// +/// # Integration Notes +/// Used in exponential bonding curve calculations +/// Critical for accurate price computations pub fn logarithm_approximation_1px(x: u256, y: u256, terms: u256) -> u256 { if x == 0 { return 0_u256; @@ -120,6 +161,9 @@ pub fn logarithm_approximation_1px(x: u256, y: u256, terms: u256) -> u256 { result } +// Get meme amount to received based on the amount_in quote token +// TODO Audit HIGH SECURITY +// Rounding and approximation issue to check pub fn get_meme_amount_exponential(pool_coin: TokenLaunch, amount_in: u256) -> u256 { let total_supply = pool_coin.total_supply.clone(); @@ -147,7 +191,26 @@ pub fn get_meme_amount_exponential(pool_coin: TokenLaunch, amount_in: u256) -> u }; amount_out } - +/// Exponential Bonding Curve Algorithm Documentation +/// +/// The exponential bonding curve implements a pricing mechanism where token price increases +/// exponentially with supply sold. This creates a steeper price curve compared to linear. +/// +/// # Key Parameters +/// - threshold_liquidity: Maximum quote tokens (e.g. ETH) that can be used to buy tokens +/// - total_supply: Total token supply +/// - sellable_supply: Amount available for sale (total_supply - liquidity reserve) +/// - LIQUIDITY_RATIO: Ratio determining liquidity reserve (e.g. 5 means 20% reserved) +/// +/// # Security Considerations +/// - Taylor series convergence at extreme values +/// - Precision loss in iterative calculations +/// - Gas costs for term computation +/// - Overflow risks in exponential growth +/// - Front-running exposure +/// - Price manipulation vectors +/// - Numerical stability at scale +/// - Edge cases: zero amounts, max supply pub fn get_coin_amount_exponential(pool_coin: TokenLaunch, amount_in: u256) -> u256 { let total_supply = pool_coin.total_supply.clone(); let current_supply = pool_coin.available_supply.clone(); @@ -173,13 +236,6 @@ pub fn get_coin_amount_exponential(pool_coin: TokenLaunch, amount_in: u256) -> u }; amount_out } - -pub fn get_coin_amount_by_quote_amount_exponential( - pool_coin: TokenLaunch, amount_in: u256 -) -> u256 { - let amount_out = 0_u256; - amount_out -} // pub fn natural_log(x: u256, scale_factor: u256, terms: u256) -> u256 { // assert!(x > 0, "Input must be greater than zero"); diff --git a/onchain/cairo/launchpad/src/launchpad/calcul/launch.cairo b/onchain/cairo/launchpad/src/launchpad/calcul/launch.cairo index 0ff760b7d..6f594b132 100644 --- a/onchain/cairo/launchpad/src/launchpad/calcul/launch.cairo +++ b/onchain/cairo/launchpad/src/launchpad/calcul/launch.cairo @@ -1,5 +1,4 @@ use afk_launchpad::launchpad::calcul::exponential::{ - get_coin_amount_by_quote_amount_exponential, // calculate_initial_price get_coin_amount_exponential, get_meme_amount_exponential }; use afk_launchpad::launchpad::calcul::linear::{ // get_coin_amount_by_quote_amount, // calculate_pricing, diff --git a/onchain/cairo/launchpad/src/launchpad/calcul/linear.cairo b/onchain/cairo/launchpad/src/launchpad/calcul/linear.cairo index 0fc654d94..932416ee6 100644 --- a/onchain/cairo/launchpad/src/launchpad/calcul/linear.cairo +++ b/onchain/cairo/launchpad/src/launchpad/calcul/linear.cairo @@ -23,6 +23,44 @@ const SAFE_SCALE: u256 = 1_000_000; // 1e6 instead of 1e18 // Get the meme amount to received based on the amount_in quote token // TODO audit // Rounding and approximation issue +/// Linear Bonding Curve Algorithm Documentation +/// +/// The linear bonding curve implements a pricing mechanism where the token price increases linearly +/// with the amount of tokens sold. This creates a fair launch mechanism where early buyers get +/// lower prices. +/// +/// # Key Parameters +/// - threshold_liquidity: Maximum amount of quote tokens (e.g. ETH) that can be used to buy tokens +/// - total_supply: Total token supply +/// - sellable_supply: Amount available for sale (total_supply - liquidity reserve) +/// - LIQUIDITY_RATIO: Ratio determining liquidity reserve (e.g. 5 means 20% reserved) +/// +/// # Key Functions +/// - get_meme_amount(): Calculates tokens received when buying +/// - get_coin_amount(): Calculates quote tokens received when selling +/// +/// # Implementation Details +/// 1. Scaling factors used to handle precision: +/// - SCALE_FACTOR: 1e30 for general calculations +/// - SCALE_ROOT_FACTOR: 1e15 for square root operations +/// - DECIMAL_FACTOR: 1e18 for token decimals +/// +/// 2. Buy Process (get_meme_amount): +/// a. Calculate current price based on tokens sold +/// b. Solve quadratic equation to determine tokens received +/// c. Apply scaling and precision handling +/// +/// 3. Sell Process (get_coin_amount): +/// a. Calculate price before and after sale +/// b. Integrate price function to determine quote tokens returned +/// c. Apply scaling and safety checks +/// +/// # Security Considerations +/// - Precision loss in calculations +/// - Overflow risks in multiplication +/// - Edge cases: zero amounts, max supply +/// - Rounding behavior impact +/// - Front-running possibilities pub fn get_meme_amount(pool_coin: TokenLaunch, amount_in: u256) -> u256 { let total_supply = pool_coin.total_supply.clone(); let current_supply = pool_coin.available_supply.clone(); @@ -58,9 +96,29 @@ pub fn get_meme_amount(pool_coin: TokenLaunch, amount_in: u256) -> u256 { amount_out } -// Get the Quote token to received based on the amount_in of meme to sell -// TODO audit +// Get the Quote token to received based on the amount_in of meme to sell based on the bonding curve +// Linear TODO audit // Rounding and approximation issue +// HIGH SECURITY RISK +// Linear Bonding Curve Algorithm Documentation +// +// The linear bonding curve implements a pricing mechanism where the token price increases linearly +// with the amount of tokens sold. The key components are: +// +// Key Parameters: +// - threshold_liquidity: Maximum amount of quote tokens (e.g. ETH) that can be used to buy +// tokens - total_supply: Total token supply +// - sellable_supply: Amount available for sale (total_supply - liquidity reserve) +// - LIQUIDITY_RATIO: Ratio determining liquidity reserve (e.g. 5 means 20% reserved) +// Key Considerations: +// - Uses scaled arithmetic to handle precision +// - Includes safety checks for zero values and thresholds +// - Maintains constant liquidity reserve ratio +// - Price increases predictably with sales volume +// +// Note: The implementation includes scaling factors and safety checks to handle +// numerical precision and prevent overflow/underflow conditions. + pub fn get_coin_amount(pool_coin: TokenLaunch, amount_in: u256) -> u256 { let total_supply = pool_coin.total_supply.clone(); let current_supply = pool_coin.available_supply.clone();