diff --git a/HARDCODE_LAUNCH_DELAY.md b/HARDCODE_LAUNCH_DELAY.md new file mode 100644 index 00000000..a4672f6c --- /dev/null +++ b/HARDCODE_LAUNCH_DELAY.md @@ -0,0 +1,701 @@ +# 🤖 AUTONOMOUS PR ORCHESTRATOR - DO NOT SKIP + +**You are an autonomous PR orchestrator. Your ONLY job is to implement this plan and create a PR.** + +## Isolation Check (RUN FIRST) +```bash +REPO_ROOT=$(git rev-parse --show-toplevel) +if [ "$REPO_ROOT" = "/home/theseus/alexandria/lbryfun" ]; then + echo "❌ FATAL: In main repo. Must be in worktree." + echo "Worktree: /home/theseus/alexandria/lbryfun-launch-delay-hardcode" + exit 1 +fi +echo "✅ In isolated worktree: $REPO_ROOT" +``` + +## Your Autonomous Workflow (NO QUESTIONS ALLOWED) +1. **Verify isolation** - You must be in worktree: `/home/theseus/alexandria/lbryfun-launch-delay-hardcode` +2. **Implement feature** - Follow plan sections below +3. **Build locally** (verification only - NEVER DEPLOY TO MAINNET): + ```bash + ./scripts/build.sh + ``` + **⚠️ PRODUCTION WARNING**: This is a live financial application. Never deploy to mainnet. +4. **Create PR** (MANDATORY): + ```bash + git add . + git commit -m "Hardcode launch delay to 24 hours, remove user configuration" + git push -u origin feature/launch-delay-hardcode + gh pr create --title "Hardcode launch delay to 24 hours" --body "Implements HARDCODE_LAUNCH_DELAY.md" + ``` +5. **Iterate autonomously**: + - FOR i=1 to 5: + - Check review: `gh pr view [NUM] --json comments` + - Count P0 issues + - IF P0 > 0: Fix immediately, commit, push, sleep 300s, continue + - IF P0 = 0: Report success, EXIT + - After 5 iterations: Escalate to human + +## CRITICAL RULES +- ❌ NO questions ("should I?", "want me to?", "is it done?") +- ❌ NO skipping PR creation - it's MANDATORY +- ❌ NO stopping after implementation - create PR immediately +- ✅ After sleep: IMMEDIATELY continue (no pause) +- ✅ ONLY stop at: approved, max iterations, or error + +**Branch:** `feature/launch-delay-hardcode` +**Worktree:** `/home/theseus/alexandria/lbryfun-launch-delay-hardcode` + +--- + +# Implementation Plan: Hardcode Launch Delay to 24 Hours + +## Task Classification +**BUG FIX / SIMPLIFICATION**: Remove unnecessary configurability, enforce 24-hour minimum launch delay + +## Current State + +### Backend Files with launch_delay_seconds + +1. **Type Definitions**: + - `src/lbry_fun/src/deployment.rs:42` - `CreateTokenParams` struct field + - `src/lbry_fun/lbry_fun.did:7` - Candid interface field + - `src/lbry_fun/src/storage.rs:56` - `TokenRecord` struct field + +2. **Validation**: + - `src/lbry_fun/src/deployment_updates.rs:409-416` - MIN/MAX validation (currently 1 second to 30 days) + +3. **Usage**: + - `src/lbry_fun/src/update.rs:47,66` - Parameter in create_token function + - `src/lbry_fun/src/update.rs:220,224-225` - Calculates launch_time from delay + - `src/lbry_fun/src/deployment_execution.rs:175,240,243` - Used in deployment + +4. **Tests**: + - `tests/unit/test_deployment_validation.rs` - Validation tests for launch_delay + +### Frontend Files with launch_delay_seconds + +1. **Type Definitions**: + - `src/lbry_fun_frontend/src/types/deployment.ts:20` - Interface field + +2. **Form Component**: + - `src/lbry_fun_frontend/src/features/token/components/terminal/TerminalCreateToken.tsx:44` - Form state field + - `src/lbry_fun_frontend/src/features/token/components/terminal/TerminalCreateToken.tsx:94` - Default value '86400' + - `src/lbry_fun_frontend/src/features/token/components/terminal/TerminalCreateToken.tsx:182-188` - Validation logic + - `src/lbry_fun_frontend/src/features/token/components/terminal/TerminalCreateToken.tsx:343-360` - Options dropdown + - `src/lbry_fun_frontend/src/features/token/components/terminal/TerminalCreateToken.tsx:694-705` - UI rendering + +3. **Display Components**: + - `src/lbry_fun_frontend/src/features/swap/components/TokenomicsTab.tsx:233-236` - Displays launch delay info + +4. **Thunks** (Pass-through only, no changes needed): + - `src/lbry_fun_frontend/src/features/token/thunk/deploymentThunks.ts` + - `src/lbry_fun_frontend/src/features/token/thunk/createToken.thunk.ts` + - `src/lbry_fun_frontend/src/features/token/thunk/getLiveTokens.thunk.ts` + - `src/lbry_fun_frontend/src/features/token/thunk/getTokenPools.thunk.ts` + - `src/lbry_fun_frontend/src/features/token/thunk/getUpcommingTokens.thunk.ts` + +### Current Behavior +- User can select launch delay from 1 second to 30 days via dropdown +- Default is 24 hours (86400 seconds) +- Both frontend and backend validate the range + +### Target Behavior +- Launch delay is ALWAYS 24 hours (86400 seconds) +- No user configuration possible +- Remove from UI form (no dropdown, no input) +- Backend hardcodes the value +- Still stored in TokenRecord for display purposes + +--- + +## Implementation + +### 1. Backend Changes + +#### File: `src/lbry_fun/src/deployment.rs` + +**MODIFY** CreateTokenParams struct: +```rust +// PSEUDOCODE +#[derive(CandidType, Deserialize, Clone, Debug)] +pub struct CreateTokenParams { + pub primary_token_name: String, + pub primary_token_symbol: String, + pub primary_token_description: String, + pub primary_logo: String, + pub secondary_token_name: String, + pub secondary_token_symbol: String, + pub secondary_token_description: String, + pub secondary_logo: String, + pub primary_max_supply: u64, + pub initial_primary_mint: u64, + pub initial_secondary_burn: u64, + pub halving_step: u64, + pub threshold_multiplier: f64, + pub initial_reward_per_burn_unit: u64, + pub distribution_interval_seconds: u64, + // REMOVE: pub launch_delay_seconds: u64, +} + +// ADD CONSTANT at module level +pub const LAUNCH_DELAY_SECONDS: u64 = 86400; // 24 hours hardcoded +``` + +#### File: `src/lbry_fun/lbry_fun.did` + +**MODIFY** CreateTokenParams type: +```candid +// PSEUDOCODE +type CreateTokenParams = record { + secondary_token_symbol : text; + primary_token_name : text; + secondary_token_description : text; + secondary_token_name : text; + primary_token_symbol : text; + // REMOVE: launch_delay_seconds : nat64; + primary_logo : text; + halving_step : nat64; + primary_token_description : text; + initial_reward_per_burn_unit : nat64; + initial_primary_mint : nat64; + threshold_multiplier : float64; + secondary_logo : text; + distribution_interval_seconds : nat64; + primary_max_supply : nat64; + initial_secondary_burn : nat64; +}; + +// NOTE: TokenRecord KEEPS launch_delay_seconds for display +// No changes needed to TokenRecord in .did file +``` + +**MODIFY** create_token function signature: +```candid +// PSEUDOCODE +service : () -> { + create_token : ( + text, // primary_token_name + text, // primary_token_symbol + text, // primary_token_description + text, // primary_logo + text, // secondary_token_name + text, // secondary_token_symbol + text, // secondary_token_description + text, // secondary_logo + nat64, // primary_max_supply + nat64, // initial_primary_mint + nat64, // initial_secondary_burn + nat64, // halving_step + float64, // threshold_multiplier + nat64, // initial_reward_per_burn_unit + nat64, // distribution_interval_seconds + // REMOVE: nat64 (launch_delay_seconds) + ) -> (Result); + + // ... rest of service definition unchanged +} +``` + +#### File: `src/lbry_fun/src/update.rs` + +**MODIFY** create_token function: +```rust +// PSEUDOCODE +#[ic_cdk::update] +async fn create_token( + primary_token_name: String, + primary_token_symbol: String, + primary_token_description: String, + primary_logo: String, + secondary_token_name: String, + secondary_token_symbol: String, + secondary_token_description: String, + secondary_logo: String, + primary_max_supply: u64, + initial_primary_mint: u64, + initial_secondary_burn: u64, + halving_step: u64, + threshold_multiplier: f64, + initial_reward_per_burn_unit: u64, + distribution_interval_seconds: u64, + // REMOVE: launch_delay_seconds: u64, +) -> Result { + // Use hardcoded constant instead + let params = CreateTokenParams { + primary_token_name, + primary_token_symbol, + primary_token_description, + primary_logo, + secondary_token_name, + secondary_token_symbol, + secondary_token_description, + secondary_logo, + primary_max_supply, + initial_primary_mint, + initial_secondary_burn, + halving_step, + threshold_multiplier, + initial_reward_per_burn_unit, + distribution_interval_seconds, + // REMOVE: launch_delay_seconds, + }; + + // Phase 1: Initiate deployment + let deployment_id = initiate_token_deployment(params).await?; + + // Phase 2: Execute deployment + let result = execute_token_deployment(deployment_id).await?; + + Ok(format!("Token created successfully (ID: {})", result.token_id)) +} +``` + +**MODIFY** install_icp_swap_wasm_on_existing_canister function: +```rust +// PSEUDOCODE +pub async fn install_icp_swap_wasm_on_existing_canister( + canister_id: Principal, + primary_token_id: Option, + secondary_token_id: Option, + tokenomics_canister_id: Option, + distribution_interval_seconds: u64, + // REMOVE: launch_delay_seconds: u64, + token_id: Option, +) -> Result<(), String> { + // Use hardcoded constant + use crate::deployment::LAUNCH_DELAY_SECONDS; + + let launch_time = if LAUNCH_DELAY_SECONDS > 0 { + Some(ic_cdk::api::time() / 1_000_000_000 + LAUNCH_DELAY_SECONDS) + } else { + None + }; + + let args = IcpSwapInitArgs { + token_id, + primary_token_id, + secondary_token_id, + tokenomics_canister_id, + icp_ledger_id: None, + distribution_interval_seconds, + launch_time, + }; + + // ... rest of function unchanged +} +``` + +#### File: `src/lbry_fun/src/deployment_updates.rs` + +**MODIFY** validate_deployment_params function: +```rust +// PSEUDOCODE +async fn validate_deployment_params(params: &CreateTokenParams) -> Result<(), String> { + // ... existing validation ... + + // REMOVE: All launch_delay_seconds validation (lines 408-417) + // const MIN_LAUNCH_DELAY: u64 = 1; + // const MAX_LAUNCH_DELAY: u64 = 2_592_000; + // if params.launch_delay_seconds < MIN_LAUNCH_DELAY { ... } + // if params.launch_delay_seconds > MAX_LAUNCH_DELAY { ... } + + // No validation needed - it's hardcoded! + + // ... rest of validation unchanged ... + Ok(()) +} +``` + +#### File: `src/lbry_fun/src/deployment_execution.rs` + +**MODIFY** execute_deployment_safe function: +```rust +// PSEUDOCODE +pub async fn execute_deployment_safe(deployment_id: u64) -> Result { + use crate::deployment::LAUNCH_DELAY_SECONDS; + + // ... existing code ... + + ic_cdk::println!("[DEPLOYMENT] Installing swap wasm..."); + install_icp_swap_wasm_on_existing_canister( + swap_canister_id, + Some(get_principal(&primary_token_id)), + Some(get_principal(&secondary_token_id)), + Some(tokenomics_canister_id), + params.distribution_interval_seconds, + // REMOVE: params.launch_delay_seconds, + Some(token_id), + ) + .await?; + + // ... more code ... + + let mut token_record = TokenRecord { + id: 0, + status: crate::storage::TokenStatus::Deploying { progress: 80 }, + // ... other fields ... + distribution_interval_seconds: params.distribution_interval_seconds, + launch_delay_seconds: LAUNCH_DELAY_SECONDS, // Use constant + caller, + created_time: ic_cdk::api::time(), + launched_at: ic_cdk::api::time() + LAUNCH_DELAY_SECONDS * 1_000_000_000, // Use constant + codebase_version: crate::CODEBASE_VERSION.to_string(), + }; + + // ... rest of function unchanged ... +} +``` + +#### File: `tests/unit/test_deployment_validation.rs` + +**MODIFY** test cases: +```rust +// PSEUDOCODE +#[test] +fn test_validate_launch_delay() { + // REMOVE entire test function + // Launch delay is now hardcoded, no validation needed +} + +// UPDATE other test functions to remove launch_delay_seconds parameter +#[test] +fn test_valid_params() { + let params = CreateTokenParams { + // ... other fields ... + distribution_interval_seconds: 3600, + // REMOVE: launch_delay_seconds: 86400, + }; + + // ... rest of test unchanged ... +} + +// Repeat for all test functions that construct CreateTokenParams +``` + +--- + +### 2. Frontend Changes + +#### File: `src/lbry_fun_frontend/src/types/deployment.ts` + +**MODIFY** CreateTokenParams interface: +```typescript +// PSEUDOCODE +export interface CreateTokenParams { + primary_token_name: string; + primary_token_symbol: string; + primary_token_description: string; + primary_logo: string; + secondary_token_name: string; + secondary_token_symbol: string; + secondary_token_description: string; + secondary_logo: string; + primary_max_supply: bigint; + initial_primary_mint: bigint; + initial_secondary_burn: bigint; + halving_step: bigint; + threshold_multiplier: number; + initial_reward_per_burn_unit: bigint; + distribution_interval_seconds: bigint; + // REMOVE: launch_delay_seconds: bigint; +} + +// ADD CONSTANT at module level +export const LAUNCH_DELAY_SECONDS = 86400n; // 24 hours hardcoded +``` + +#### File: `src/lbry_fun_frontend/src/features/token/components/terminal/TerminalCreateToken.tsx` + +**MODIFY** TokenFormValues interface: +```typescript +// PSEUDOCODE +interface TokenFormValues { + primary_token_symbol: string; + primary_token_name: string; + primary_token_description: string; + secondary_token_symbol: string; + secondary_token_name: string; + secondary_token_description: string; + secondary_token_logo_base64: string; + primary_max_supply: string; + tge_allocation: string; + initial_secondary_burn: string; + primary_token_logo_base64: string; + halving_step: string; + threshold_multiplier: string; + initial_reward_per_burn_unit: string; + distribution_interval_seconds: string; + // REMOVE: launch_delay_seconds: string; +} +``` + +**MODIFY** form state initialization: +```typescript +// PSEUDOCODE +const [form, setForm] = useState({ + primary_token_symbol: '', + primary_token_name: '', + primary_token_description: '', + secondary_token_symbol: '', + secondary_token_name: '', + secondary_token_description: '', + secondary_token_logo_base64: '', + primary_max_supply: '1000000000', + tge_allocation: '0', + initial_secondary_burn: '1000000', + primary_token_logo_base64: '', + halving_step: '90', + threshold_multiplier: '1.5', + initial_reward_per_burn_unit: '1', + distribution_interval_seconds: '3600', + // REMOVE: launch_delay_seconds: '86400', +}); +``` + +**REMOVE** launchDelayOptions array: +```typescript +// PSEUDOCODE +// DELETE lines 343-360 +// const launchDelayOptions = [ ... ]; +``` + +**REMOVE** launch_delay validation: +```typescript +// PSEUDOCODE +// In useEffect validation, DELETE lines 181-189: +// // Validate launch delay +// const launchDelay = parseInt(form.launch_delay_seconds); +// if (!form.launch_delay_seconds || isNaN(launchDelay)) { +// newErrors.launch_delay_seconds = 'Launch delay is required'; +// } else if (launchDelay < 1) { +// newErrors.launch_delay_seconds = 'Launch delay must be at least 1 second'; +// } else if (launchDelay > 2592000) { +// newErrors.launch_delay_seconds = 'Launch delay cannot exceed 30 days'; +// } +``` + +**REMOVE** launch_delay UI section: +```typescript +// PSEUDOCODE +// In JSX advanced_settings section, DELETE lines 693-705: +//
+// launch_delay +// +//
+// updateForm('launch_delay_seconds', v)} +// options={launchDelayOptions} +// /> +//
...
+``` + +**ADD** informational text in advanced section: +```typescript +// PSEUDOCODE +// After distribution_interval section, ADD: +
+
+ launch_delay + +
+
24_hours [fixed]
+
Trading will be enabled 24 hours after creation.
+
+``` + +**MODIFY** handleInitiateDeployment function: +```typescript +// PSEUDOCODE +const handleInitiateDeployment = async () => { + // ... existing validation ... + + const params: CreateTokenParams = { + primary_token_name: form.primary_token_name, + primary_token_symbol: form.primary_token_symbol, + primary_token_description: form.primary_token_description, + primary_logo: form.primary_token_logo_base64, + secondary_token_name: form.secondary_token_name, + secondary_token_symbol: form.secondary_token_symbol, + secondary_token_description: form.secondary_token_description, + secondary_logo: form.secondary_token_logo_base64, + primary_max_supply: BigInt(form.primary_max_supply), + initial_primary_mint: BigInt(form.tge_allocation), + initial_secondary_burn: BigInt(form.initial_secondary_burn), + halving_step: BigInt(form.halving_step), + threshold_multiplier: parseFloat(form.threshold_multiplier), + initial_reward_per_burn_unit: TokenConversionService.naturalToE8s(form.initial_reward_per_burn_unit), + distribution_interval_seconds: BigInt(form.distribution_interval_seconds), + // REMOVE: launch_delay_seconds: BigInt(form.launch_delay_seconds) + }; + + // ... rest of function unchanged ... +}; +``` + +#### File: `src/lbry_fun_frontend/src/features/token/thunk/createToken.thunk.ts` + +**MODIFY** createToken thunk: +```typescript +// PSEUDOCODE +import { LAUNCH_DELAY_SECONDS } from '../../../types/deployment'; + +export const createToken = createAsyncThunk( + 'token/createToken', + async (formData: any, { dispatch }) => { + // ... existing code ... + + const result = await lbryFunActor.create_token( + formData.primary_token_name, + formData.primary_token_symbol, + formData.primary_token_description, + formData.primary_logo, + formData.secondary_token_name, + formData.secondary_token_symbol, + formData.secondary_token_description, + formData.secondary_logo, + BigInt(formData.primary_max_supply), + BigInt(formData.initial_primary_mint), + BigInt(formData.initial_secondary_burn), + BigInt(formData.halving_step), + formData.threshold_multiplier, + BigInt(formData.initial_reward_per_burn_unit), + BigInt(formData.distribution_interval_seconds), + // REMOVE: BigInt(formData.launch_delay_seconds) + ); + + // ... rest of thunk unchanged ... + } +); +``` + +#### File: `src/lbry_fun_frontend/src/features/token/thunk/deploymentThunks.ts` + +**MODIFY** initiateDeployment thunk: +```typescript +// PSEUDOCODE +import { LAUNCH_DELAY_SECONDS } from '../../../types/deployment'; + +export const initiateDeployment = createAsyncThunk( + 'deployment/initiate', + async (params: CreateTokenParams, { rejectWithValue }) => { + // ... existing code ... + + const candidParams = { + primary_token_name: params.primary_token_name, + // ... other fields ... + distribution_interval_seconds: params.distribution_interval_seconds, + // REMOVE: launch_delay_seconds: params.launch_delay_seconds + }; + + // ... rest of thunk unchanged ... + } +); + +// UPDATE executeDeployment if it reconstructs params +// Generally no changes needed as it just passes deployment_id +``` + +#### File: `src/lbry_fun_frontend/src/features/swap/components/TokenomicsTab.tsx` + +**MODIFY** display to show hardcoded value with note: +```typescript +// PSEUDOCODE +// Around line 233-236, MODIFY: +
+ + launch_delay: + + + + {formatTimeInterval(tokenConfig.launch_delay_seconds)} [fixed] + +
+``` + +--- + +## Testing Requirements + +### Local Build Verification +```bash +cd /home/theseus/alexandria/lbryfun-launch-delay-hardcode +./scripts/build.sh +``` + +**Expected Results:** +- ✅ All canisters compile successfully +- ✅ Frontend builds without TypeScript errors +- ✅ No warnings about missing launch_delay_seconds parameters + +### Manual Verification (Optional) +If testing locally: +1. Create a token through the UI +2. Verify form no longer shows launch_delay dropdown +3. Verify "24_hours [fixed]" is displayed in advanced section +4. Verify token is created with 24-hour launch delay +5. Verify TokenomicsTab displays launch delay correctly + +**⚠️ CRITICAL**: Never deploy to mainnet - this is a production app with financial consequences. + +--- + +## Files Modified Summary + +### Backend (8 files) +1. ✏️ `src/lbry_fun/src/deployment.rs` - Remove field, add constant +2. ✏️ `src/lbry_fun/lbry_fun.did` - Update CreateTokenParams, create_token signature +3. ✏️ `src/lbry_fun/src/update.rs` - Remove parameter, use constant +4. ✏️ `src/lbry_fun/src/deployment_updates.rs` - Remove validation +5. ✏️ `src/lbry_fun/src/deployment_execution.rs` - Use constant instead of param +6. ✏️ `tests/unit/test_deployment_validation.rs` - Update tests + +### Frontend (5 files) +1. ✏️ `src/lbry_fun_frontend/src/types/deployment.ts` - Remove field, add constant +2. ✏️ `src/lbry_fun_frontend/src/features/token/components/terminal/TerminalCreateToken.tsx` - Remove UI, validation, options +3. ✏️ `src/lbry_fun_frontend/src/features/token/thunk/createToken.thunk.ts` - Remove parameter +4. ✏️ `src/lbry_fun_frontend/src/features/token/thunk/deploymentThunks.ts` - Remove parameter +5. ✏️ `src/lbry_fun_frontend/src/features/swap/components/TokenomicsTab.tsx` - Update display + +### No Changes Needed +- `src/lbry_fun/src/storage.rs` - TokenRecord keeps launch_delay_seconds for display +- Other thunk files - Only pass through data, no reconstruction needed + +--- + +## Review Checklist + +- [ ] Backend constant LAUNCH_DELAY_SECONDS = 86400 defined +- [ ] CreateTokenParams struct no longer has launch_delay_seconds field +- [ ] Candid interface updated (both type and function signature) +- [ ] create_token function signature updated (removed parameter) +- [ ] Validation code removed from deployment_updates.rs +- [ ] install_icp_swap_wasm_on_existing_canister uses constant +- [ ] execute_deployment_safe uses constant for TokenRecord +- [ ] Tests updated to remove launch_delay_seconds +- [ ] Frontend CreateTokenParams interface updated +- [ ] Form state no longer includes launch_delay_seconds +- [ ] launchDelayOptions array removed +- [ ] Validation logic for launch_delay removed +- [ ] UI dropdown section removed +- [ ] Informational text added showing "24_hours [fixed]" +- [ ] createToken thunk updated (parameter removed) +- [ ] initiateDeployment thunk updated (parameter removed) +- [ ] TokenomicsTab updated to show "[fixed]" label +- [ ] Build passes successfully +- [ ] No TypeScript errors +- [ ] PR created and pushed + +--- + +## Success Criteria + +✅ Launch delay is hardcoded to 24 hours throughout the system +✅ User cannot configure launch delay in UI +✅ UI clearly shows "24_hours [fixed]" in advanced section +✅ Backend enforces 24-hour delay without user input +✅ All existing tokens with different delays still display correctly +✅ Build completes successfully +✅ PR created automatically diff --git a/src/lbry_fun/lbry_fun.did b/src/lbry_fun/lbry_fun.did index bc53b031..24d35e3b 100644 --- a/src/lbry_fun/lbry_fun.did +++ b/src/lbry_fun/lbry_fun.did @@ -4,7 +4,6 @@ type CreateTokenParams = record { secondary_token_description : text; secondary_token_name : text; primary_token_symbol : text; - launch_delay_seconds : nat64; primary_logo : text; halving_step : nat64; primary_token_description : text; @@ -120,7 +119,6 @@ service : () -> { float64, nat64, nat64, - nat64, ) -> (Result); // Phase 2: Execute the deployment with the given ID execute_token_deployment : (nat64) -> (Result_1); diff --git a/src/lbry_fun/src/deployment.rs b/src/lbry_fun/src/deployment.rs index 5fef862a..16327b1c 100644 --- a/src/lbry_fun/src/deployment.rs +++ b/src/lbry_fun/src/deployment.rs @@ -9,6 +9,10 @@ use std::{borrow::Cow, cell::RefCell}; type Memory = VirtualMemory; +/// Launch delay enforced for all tokens to prevent bot sniping and ensure fair launch. +/// Fixed at 24 hours (86400 seconds) to give all users equal opportunity to participate. +pub const LAUNCH_DELAY_SECONDS: u64 = 86400; + // Memory IDs for stable structures pub const DEPLOYMENTS_MEM_ID: MemoryId = MemoryId::new(10); pub const USER_ACTIVE_DEPLOYMENTS_MEM_ID: MemoryId = MemoryId::new(11); @@ -39,7 +43,6 @@ pub struct CreateTokenParams { pub threshold_multiplier: f64, pub initial_reward_per_burn_unit: u64, pub distribution_interval_seconds: u64, - pub launch_delay_seconds: u64, } #[derive(CandidType, Deserialize, Clone, Debug)] diff --git a/src/lbry_fun/src/deployment_execution.rs b/src/lbry_fun/src/deployment_execution.rs index c3e07ffb..62f2f9c0 100644 --- a/src/lbry_fun/src/deployment_execution.rs +++ b/src/lbry_fun/src/deployment_execution.rs @@ -172,7 +172,6 @@ pub async fn execute_deployment_safe(deployment_id: u64) -> Result Some(get_principal(&secondary_token_id)), Some(tokenomics_canister_id), params.distribution_interval_seconds, - params.launch_delay_seconds, Some(token_id), // Pass the correct token_id ) .await?; @@ -237,10 +236,10 @@ pub async fn execute_deployment_safe(deployment_id: u64) -> Result threshold_multiplier: params.threshold_multiplier, initial_reward_per_burn_unit: params.initial_reward_per_burn_unit, distribution_interval_seconds: params.distribution_interval_seconds, - launch_delay_seconds: params.launch_delay_seconds, + launch_delay_seconds: crate::deployment::LAUNCH_DELAY_SECONDS, caller, created_time: ic_cdk::api::time(), - launched_at: ic_cdk::api::time() + params.launch_delay_seconds * 1_000_000_000, + launched_at: ic_cdk::api::time() + crate::deployment::LAUNCH_DELAY_SECONDS * 1_000_000_000, codebase_version: crate::CODEBASE_VERSION.to_string(), }; diff --git a/src/lbry_fun/src/deployment_updates.rs b/src/lbry_fun/src/deployment_updates.rs index 0778b2fc..00d08a4b 100644 --- a/src/lbry_fun/src/deployment_updates.rs +++ b/src/lbry_fun/src/deployment_updates.rs @@ -404,18 +404,7 @@ async fn validate_deployment_params(params: &CreateTokenParams) -> Result<(), St if params.threshold_multiplier < 1.0 || params.threshold_multiplier > 10.0 { return Err("Threshold multiplier must be between 1.0 and 10.0".to_string()); } - - // Launch delay validation (sent as seconds: 1 second to 30 days) - const MIN_LAUNCH_DELAY: u64 = 1; - const MAX_LAUNCH_DELAY: u64 = 2_592_000; // 30 days in seconds - - if params.launch_delay_seconds < MIN_LAUNCH_DELAY { - return Err("Launch delay must be at least 1 second".to_string()); - } - if params.launch_delay_seconds > MAX_LAUNCH_DELAY { - return Err("Launch delay cannot exceed 30 days".to_string()); - } - + // Distribution interval validation (sent as seconds, min 60) if params.distribution_interval_seconds < 60 { return Err("Distribution interval must be at least 60 seconds".to_string()); diff --git a/src/lbry_fun/src/update.rs b/src/lbry_fun/src/update.rs index e09df0cb..47e3622f 100644 --- a/src/lbry_fun/src/update.rs +++ b/src/lbry_fun/src/update.rs @@ -44,7 +44,6 @@ async fn create_token( threshold_multiplier: f64, initial_reward_per_burn_unit: u64, distribution_interval_seconds: u64, - launch_delay_seconds: u64, ) -> Result { // Use the new two-phase deployment system internally let params = CreateTokenParams { @@ -63,7 +62,6 @@ async fn create_token( threshold_multiplier, initial_reward_per_burn_unit, distribution_interval_seconds, - launch_delay_seconds, }; // Phase 1: Initiate deployment @@ -217,12 +215,13 @@ pub async fn install_icp_swap_wasm_on_existing_canister( secondary_token_id: Option, tokenomics_canister_id: Option, distribution_interval_seconds: u64, - launch_delay_seconds: u64, token_id: Option, // Add token_id parameter ) -> Result<(), String> { - // Calculate launch_time from current time + delay - let launch_time = if launch_delay_seconds > 0 { - Some(ic_cdk::api::time() / 1_000_000_000 + launch_delay_seconds) + // Use hardcoded 24-hour launch delay + use crate::deployment::LAUNCH_DELAY_SECONDS; + + let launch_time = if LAUNCH_DELAY_SECONDS > 0 { + Some(ic_cdk::api::time() / 1_000_000_000 + LAUNCH_DELAY_SECONDS) } else { None }; diff --git a/src/lbry_fun_frontend/src/features/swap/components/TokenomicsTab.tsx b/src/lbry_fun_frontend/src/features/swap/components/TokenomicsTab.tsx index 21b67061..dd55f1fa 100644 --- a/src/lbry_fun_frontend/src/features/swap/components/TokenomicsTab.tsx +++ b/src/lbry_fun_frontend/src/features/swap/components/TokenomicsTab.tsx @@ -231,9 +231,9 @@ const TokenomicsTab: React.FC = () => {
launch_delay: - + - {formatTimeInterval(tokenConfig.launch_delay_seconds)} + {formatTimeInterval(tokenConfig.launch_delay_seconds)} [fixed]
{/* Metadata */} diff --git a/src/lbry_fun_frontend/src/features/token/components/terminal/TerminalCreateToken.tsx b/src/lbry_fun_frontend/src/features/token/components/terminal/TerminalCreateToken.tsx index 4249e4ba..b9354366 100644 --- a/src/lbry_fun_frontend/src/features/token/components/terminal/TerminalCreateToken.tsx +++ b/src/lbry_fun_frontend/src/features/token/components/terminal/TerminalCreateToken.tsx @@ -41,7 +41,6 @@ export interface TokenFormValues { threshold_multiplier: string; initial_reward_per_burn_unit: string; distribution_interval_seconds: string; - launch_delay_seconds: string; } interface FormErrors { @@ -91,7 +90,6 @@ const TerminalCreateToken: React.FC = () => { threshold_multiplier: '1.5', initial_reward_per_burn_unit: '1', distribution_interval_seconds: '3600', - launch_delay_seconds: '86400', }); // Validation logic @@ -178,16 +176,6 @@ const TerminalCreateToken: React.FC = () => { newErrors.threshold_multiplier = 'Must be between 1 and 10'; } - // Validate launch delay - const launchDelay = parseInt(form.launch_delay_seconds); - if (!form.launch_delay_seconds || isNaN(launchDelay)) { - newErrors.launch_delay_seconds = 'Launch delay is required'; - } else if (launchDelay < 1) { - newErrors.launch_delay_seconds = 'Launch delay must be at least 1 second'; - } else if (launchDelay > 2592000) { // 30 days in seconds - newErrors.launch_delay_seconds = 'Launch delay cannot exceed 30 days'; - } - setErrors(newErrors); setWarnings(newWarnings); }, [form]); @@ -300,7 +288,6 @@ const TerminalCreateToken: React.FC = () => { threshold_multiplier: parseFloat(form.threshold_multiplier), initial_reward_per_burn_unit: BigInt(Math.floor(parseFloat(form.initial_reward_per_burn_unit) * Number(TokenConversionService.getE8S()))), distribution_interval_seconds: BigInt(form.distribution_interval_seconds), - launch_delay_seconds: BigInt(form.launch_delay_seconds) }; // Phase 1: Initiate deployment @@ -340,25 +327,6 @@ const TerminalCreateToken: React.FC = () => { { value: '86400', label: '24_hours' }, ]; - const launchDelayOptions = [ - { value: '1', label: '1_second' }, - { value: '60', label: '1_minute' }, - { value: '300', label: '5_minutes' }, - { value: '900', label: '15_minutes' }, - { value: '1800', label: '30_minutes' }, - { value: '3600', label: '1_hour' }, - { value: '7200', label: '2_hours' }, - { value: '14400', label: '4_hours' }, - { value: '28800', label: '8_hours' }, - { value: '43200', label: '12_hours' }, - { value: '86400', label: '24_hours [default]' }, - { value: '172800', label: '2_days' }, - { value: '259200', label: '3_days' }, - { value: '604800', label: '7_days' }, - { value: '1209600', label: '14_days' }, - { value: '2592000', label: '30_days' }, - ]; - return (
{/* Header */} @@ -689,20 +657,15 @@ const TerminalCreateToken: React.FC = () => { options={distributionIntervalOptions} />
Cannot be changed after creation.
- -
- launch_delay - + +
+
+ launch_delay + +
+
24_hours [fixed]
+
Trading will be enabled 24 hours after creation.
- updateForm('launch_delay_seconds', v)} - options={launchDelayOptions} - /> -
[INFO] Trading will be enabled after this delay. Default (24 hours) prevents bot sniping.
)}
diff --git a/src/lbry_fun_frontend/src/features/token/thunk/createToken.thunk.ts b/src/lbry_fun_frontend/src/features/token/thunk/createToken.thunk.ts index 66daf5da..6163d7e6 100644 --- a/src/lbry_fun_frontend/src/features/token/thunk/createToken.thunk.ts +++ b/src/lbry_fun_frontend/src/features/token/thunk/createToken.thunk.ts @@ -79,8 +79,7 @@ const createToken = createAsyncThunk< BigInt(formData.halving_step), formData.threshold_multiplier, BigInt(formData.initial_reward_per_burn_unit), - BigInt(formData.distribution_interval_seconds), - BigInt(formData.launch_delay_seconds) + BigInt(formData.distribution_interval_seconds) ); if ("Ok" in result) { diff --git a/src/lbry_fun_frontend/src/features/token/thunk/deploymentThunks.ts b/src/lbry_fun_frontend/src/features/token/thunk/deploymentThunks.ts index 258f8b16..3de54517 100644 --- a/src/lbry_fun_frontend/src/features/token/thunk/deploymentThunks.ts +++ b/src/lbry_fun_frontend/src/features/token/thunk/deploymentThunks.ts @@ -44,8 +44,7 @@ const persistDeployment = (deployment: DeploymentRecord) => { initial_secondary_burn: deployment.params.initial_secondary_burn.toString(), halving_step: deployment.params.halving_step.toString(), initial_reward_per_burn_unit: deployment.params.initial_reward_per_burn_unit.toString(), - distribution_interval_seconds: deployment.params.distribution_interval_seconds.toString(), - launch_delay_seconds: deployment.params.launch_delay_seconds.toString() + distribution_interval_seconds: deployment.params.distribution_interval_seconds.toString() } }, expires: Date.now() + DEPLOYMENT_TTL @@ -79,8 +78,7 @@ const loadPersistedDeployments = (): DeploymentRecord[] => { initial_secondary_burn: BigInt(deployment.params.initial_secondary_burn), halving_step: BigInt(deployment.params.halving_step), initial_reward_per_burn_unit: BigInt(deployment.params.initial_reward_per_burn_unit), - distribution_interval_seconds: BigInt(deployment.params.distribution_interval_seconds), - launch_delay_seconds: BigInt(deployment.params.launch_delay_seconds) + distribution_interval_seconds: BigInt(deployment.params.distribution_interval_seconds) } }); } else { diff --git a/src/lbry_fun_frontend/src/types/deployment.ts b/src/lbry_fun_frontend/src/types/deployment.ts index c620964c..e6fe028f 100644 --- a/src/lbry_fun_frontend/src/types/deployment.ts +++ b/src/lbry_fun_frontend/src/types/deployment.ts @@ -1,5 +1,8 @@ import { Principal } from '@dfinity/principal'; +// Launch delay constant (24 hours hardcoded) +export const LAUNCH_DELAY_SECONDS = 86400n; + // Token creation parameters export interface CreateTokenParams { primary_token_name: string; @@ -17,7 +20,6 @@ export interface CreateTokenParams { threshold_multiplier: number; initial_reward_per_burn_unit: bigint; distribution_interval_seconds: bigint; - launch_delay_seconds: bigint; } // Backend deployment info (from get_my_deployments) diff --git a/tests/unit/test_deployment_validation.rs b/tests/unit/test_deployment_validation.rs index 3f0f5303..a0cbaf92 100644 --- a/tests/unit/test_deployment_validation.rs +++ b/tests/unit/test_deployment_validation.rs @@ -190,25 +190,7 @@ fn test_deployment_parameter_validation() { }, "Threshold multiplier must be between 1.0 and 10.0" ), - - // Launch delay validation tests - ( - "launch_delay_too_low", - CreateTokenParams { - launch_delay_seconds: 0, // Less than 1 second - ..default_params() - }, - "Launch delay must be at least 1 second" - ), - ( - "launch_delay_too_high", - CreateTokenParams { - launch_delay_seconds: 2_592_001, // More than 30 days - ..default_params() - }, - "Launch delay cannot exceed 30 days" - ), - + // Distribution interval validation tests ( "distribution_interval_too_low", @@ -306,11 +288,10 @@ fn default_params() -> CreateTokenParams { threshold_multiplier: 1.5, initial_reward_per_burn_unit: 100_000_000, // 1 token in E8S distribution_interval_seconds: 3600, - launch_delay_seconds: 86400, } } -#[derive(Clone)] +#[derive(Clone, candid::CandidType, candid::Deserialize)] struct CreateTokenParams { pub primary_token_name: String, pub primary_token_symbol: String, @@ -327,5 +308,4 @@ struct CreateTokenParams { pub threshold_multiplier: f64, pub initial_reward_per_burn_unit: u64, pub distribution_interval_seconds: u64, - pub launch_delay_seconds: u64, } \ No newline at end of file