diff --git a/app/.gitignore b/app/.gitignore index 461172f..7fab50a 100644 --- a/app/.gitignore +++ b/app/.gitignore @@ -40,3 +40,6 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts + +# claude +.claude \ No newline at end of file diff --git a/app/public/tokens/usdc.svg b/app/public/tokens/usdc.svg new file mode 100644 index 0000000..93081fb --- /dev/null +++ b/app/public/tokens/usdc.svg @@ -0,0 +1,8 @@ + + + Usdc Streamline Icon: https://streamlinehq.com + + + + + \ No newline at end of file diff --git a/app/public/tokens/usdt.png b/app/public/tokens/usdt.png new file mode 100644 index 0000000..97ab8ce Binary files /dev/null and b/app/public/tokens/usdt.png differ diff --git a/app/src/components/create-token/custom/authority.tsx b/app/src/components/create-token/custom/authority.tsx index 362df8d..1602d43 100644 --- a/app/src/components/create-token/custom/authority.tsx +++ b/app/src/components/create-token/custom/authority.tsx @@ -41,7 +41,7 @@ export default function Authority({ initialData }: AuthorityProps) { const [formData, setFormData] = useState({ - tokenUpdateAuthority: initialData?.tokenUpdateAuthority || "1", + tokenUpdateAuthority: initialData?.tokenUpdateAuthority || "0", leftoverReceiver: initialData?.leftoverReceiver || "", feeClaimer: initialData?.feeClaimer || "", }); diff --git a/app/src/components/create-token/custom/dbc-config.tsx b/app/src/components/create-token/custom/dbc-config.tsx index 087efa5..3ca90ca 100644 --- a/app/src/components/create-token/custom/dbc-config.tsx +++ b/app/src/components/create-token/custom/dbc-config.tsx @@ -1,13 +1,15 @@ "use client" -import React, { useState } from 'react'; +import React, { useState, useMemo } from 'react'; +import { toast } from 'sonner'; import { Progress } from '@/components/ui/progress'; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger } from '@/components/ui/dropdown-menu'; +import { InfoTooltip, DBC_TOOLTIPS } from '@/components/ui/info-tooltip'; interface DBCConfigProps { onNext: (data: DBCConfigData) => void; @@ -20,57 +22,71 @@ interface DBCConfigProps { export interface DBCConfigData { buildCurveMode: "0" | "1" | "2" | "3"; - percentageSupplyOnMigration: number; - migrationQuoteThreshold: number; + // Mode 0 fields + percentageSupplyOnMigration?: number; + migrationQuoteThreshold?: number; + // Mode 1, 2, 3 fields + initialMarketCap?: number; + migrationMarketCap?: number; + // Mode 3 only + liquidityWeights?: number[]; + // General fields migrationOption: "0" | "1"; dynamicFeeEnabled: boolean; activationType: "0" | "1"; collectFeeMode: "0" | "1"; - migrationFeeOption: "0" | "1" | "2" | "3" | "4" | "5"; + migrationFeeOption: "0" | "1" | "2" | "3" | "4" | "5" | "6"; tokenType: "0" | "1"; + // Migrated Pool Fee (only for DAMM v2 + Customizable) + migratedPoolFee?: { + collectFeeMode: "0" | "1"; + dynamicFee: "0" | "1"; + poolFeeBps: number; + }; } const buildCurveModes = [ - { value: "0", label: "Linear" }, - { value: "1", label: "Exponential" }, - { value: "2", label: "Logarithmic" }, - { value: "3", label: "Custom" } + { value: "0", label: "Build Curve", description: "Configure curve with specific migration threshold and supply" }, + { value: "1", label: "Market Cap Based", description: "Curve based on initial and migration market cap" }, + { value: "2", label: "Two Segments", description: "Dual constant product curve with 2 segments" }, + { value: "3", label: "Liquidity Weights", description: "Custom curve with liquidity weights" } ]; const migrationOptions = [ - { value: "0", label: "Automatic" }, - { value: "1", label: "Manual" } + { value: "0", label: "DAMM v1", description: "Migrate to DAMM v1 pool" }, + { value: "1", label: "DAMM v2", description: "Migrate to DAMM v2 pool (recommended)" } ]; const activationTypes = [ - { value: "0", label: "Immediate" }, - { value: "1", label: "Delayed" } + { value: "0", label: "Slot (400ms)", description: "Measured in slots" }, + { value: "1", label: "Timestamp (seconds)", description: "Measured in seconds" } ]; const collectFeeModes = [ - { value: "0", label: "Continuous" }, - { value: "1", label: "Batch" } + { value: "0", label: "Quote Token", description: "Collect fees in quote token" }, + { value: "1", label: "Output Token", description: "Collect fees in output token" } ]; const migrationFeeOptions = [ - { value: "0", label: "No Fee" }, - { value: "1", label: "Fixed Fee" }, - { value: "2", label: "Percentage Fee" }, - { value: "3", label: "Tiered Fee" }, - { value: "4", label: "Dynamic Fee" }, - { value: "5", label: "Custom Fee" } + { value: "0", label: "LP Fee 0.25%", description: "0.25% LP fee" }, + { value: "1", label: "LP Fee 0.3%", description: "0.3% LP fee" }, + { value: "2", label: "LP Fee 1%", description: "1% LP fee" }, + { value: "3", label: "LP Fee 2%", description: "2% LP fee (recommended)" }, + { value: "4", label: "LP Fee 4%", description: "4% LP fee" }, + { value: "5", label: "LP Fee 6%", description: "6% LP fee" }, + { value: "6", label: "Customizable", description: "Custom (DAMM v2 only)" } ]; const tokenTypes = [ - { value: "0", label: "Standard" }, - { value: "1", label: "Governance" } + { value: "0", label: "SPL Token", description: "Standard SPL token" }, + { value: "1", label: "Token 2022", description: "Token following Token-2022 standard" } ]; -export default function DBCConfig({ - onNext, +export default function DBCConfig({ + onNext, onBack, - onCancel, - currentStep = 2, + onCancel, + currentStep = 2, totalSteps = 7, initialData }: DBCConfigProps) { @@ -78,25 +94,82 @@ export default function DBCConfig({ buildCurveMode: initialData?.buildCurveMode || "0", percentageSupplyOnMigration: initialData?.percentageSupplyOnMigration || 20, migrationQuoteThreshold: initialData?.migrationQuoteThreshold || 100, + initialMarketCap: initialData?.initialMarketCap, + migrationMarketCap: initialData?.migrationMarketCap, + liquidityWeights: initialData?.liquidityWeights || Array(16).fill(1), migrationOption: initialData?.migrationOption || "1", - dynamicFeeEnabled: initialData?.dynamicFeeEnabled || true, + dynamicFeeEnabled: initialData?.dynamicFeeEnabled !== undefined ? initialData.dynamicFeeEnabled : true, activationType: initialData?.activationType || "1", collectFeeMode: initialData?.collectFeeMode || "0", migrationFeeOption: initialData?.migrationFeeOption || "3", tokenType: initialData?.tokenType || "0", + migratedPoolFee: initialData?.migratedPoolFee || { + collectFeeMode: "0", + dynamicFee: "0", + poolFeeBps: 100, + }, }); const progressPercentage = (currentStep / totalSteps) * 100; - const handleInputChange = (field: keyof DBCConfigData, value: string | boolean) => { + const handleInputChange = (field: keyof DBCConfigData, value: string | boolean | number) => { setFormData(prev => ({ ...prev, [field]: value })); }; + const handleLiquidityWeightChange = (index: number, value: string) => { + const numValue = parseFloat(value) || 1; + setFormData(prev => { + const newWeights = [...(prev.liquidityWeights || Array(16).fill(1))]; + newWeights[index] = numValue; + return { ...prev, liquidityWeights: newWeights }; + }); + }; + + const handleMigratedPoolFeeChange = (field: 'collectFeeMode' | 'dynamicFee' | 'poolFeeBps', value: string | number) => { + setFormData(prev => ({ + ...prev, + migratedPoolFee: { + ...prev.migratedPoolFee!, + [field]: value + } + })); + }; + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); + + // Validation based on buildCurveMode + if (formData.buildCurveMode === "0") { + if (!formData.percentageSupplyOnMigration || !formData.migrationQuoteThreshold) { + toast.error('Please fill in percentageSupplyOnMigration and migrationQuoteThreshold'); + return; + } + } else if (["1", "2"].includes(formData.buildCurveMode)) { + if (!formData.initialMarketCap || !formData.migrationMarketCap) { + toast.error('Please fill in initialMarketCap and migrationMarketCap'); + return; + } + if (formData.buildCurveMode === "2" && !formData.percentageSupplyOnMigration) { + toast.error('Please fill in percentageSupplyOnMigration'); + return; + } + } else if (formData.buildCurveMode === "3") { + if (!formData.initialMarketCap || !formData.migrationMarketCap || !formData.liquidityWeights) { + toast.error('Please fill in all required fields for Liquidity Weights mode'); + return; + } + } + onNext(formData); }; + // Determine which fields to show based on buildCurveMode + const showMode0Fields = formData.buildCurveMode === "0"; + const showMode1Fields = formData.buildCurveMode === "1"; + const showMode2Fields = formData.buildCurveMode === "2"; + const showMode3Fields = formData.buildCurveMode === "3"; + const showMarketCapFields = ["1", "2", "3"].includes(formData.buildCurveMode); + return (
{/* Header */} @@ -105,7 +178,7 @@ export default function DBCConfig({ Bonding Curve Configuration

- Configure your token's bonding curve and migration settings. + Configure your bonding curve and migration settings for your token.

@@ -115,8 +188,8 @@ export default function DBCConfig({ Step {currentStep} of {totalSteps} {Math.round(progressPercentage)}% Complete - @@ -125,75 +198,190 @@ export default function DBCConfig({ {/* Form */}
- {/* Curve Configuration */} + {/* Build Curve Mode */}
-

Curve Settings

-
-
- - - - {buildCurveModes.find(mode => mode.value === formData.buildCurveMode)?.label || 'Select mode'} - - - - - - {buildCurveModes.map(mode => ( - handleInputChange('buildCurveMode', mode.value as "0" | "1" | "2" | "3")} - > - {mode.label} - - ))} - - -
+

+ Curve Settings + +

-
-
{/* Migration Settings */}

Migration Settings

- +
-
+
-
+ {/* Migrated Pool Fee (Conditional) */} + {formData.migrationOption === "1" && formData.migrationFeeOption === "6" && ( +
+

+ Migrated Pool Fee Configuration + +

+ +
+

+ This section is only available when using DAMM v2 with Customizable fee option. +

+
+ +
+
+ + + + {formData.migratedPoolFee?.collectFeeMode === "0" ? "Quote Token" : "Output Token"} + + + + + + handleMigratedPoolFeeChange('collectFeeMode', "0")} + className="cursor-pointer" + > + Quote Token + + handleMigratedPoolFeeChange('collectFeeMode', "1")} + className="cursor-pointer" + > + Output Token + + + +
+ +
+ + + + {formData.migratedPoolFee?.dynamicFee === "0" ? "Disabled" : "Enabled"} + + + + + + handleMigratedPoolFeeChange('dynamicFee', "0")} + className="cursor-pointer" + > + Disabled + + handleMigratedPoolFeeChange('dynamicFee', "1")} + className="cursor-pointer" + > + Enabled + + + +
+ +
+ + handleMigratedPoolFeeChange('poolFeeBps', parseFloat(e.target.value))} + className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-red-500 text-sm sm:text-base" + min="10" + max="1000" + required + /> +

Minimum 10 bps (0.1%), Maximum 1000 bps (10%)

+
+
+
+ )} + {/* Advanced Settings */}

Advanced Settings

- +
-
+
-
-
-
-
-
-
@@ -331,7 +641,7 @@ export default function DBCConfig({ {/* Action Buttons */}
- -
- @@ -118,13 +158,14 @@ export default function FeeConfig({ {/* Base Fee Mode */}

Fee Mode

- +
-
+ + {/* Mode Description */} +
+

+ {baseFeeModes.find(m => m.value === formData.baseFeeMode)?.label} +

+

+ {baseFeeModes.find(m => m.value === formData.baseFeeMode)?.description} +

+
{/* Fee Scheduler Parameters */} - {isSchedulerMode && ( + {isSchedulerMode && formData.feeSchedulerParam && (

Fee Scheduler Parameters

- +
-
-
-
-
+
+
+ )} + + {/* Rate Limiter Parameters */} + {isRateLimiterMode && formData.rateLimiterParam && ( +
+

Rate Limiter Parameters

+ +
+
+ + handleRateLimiterChange('baseFeeBps', e.target.value)} + className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-red-500 text-sm sm:text-base" + min="0" + max="9900" + required + /> +

Phí cơ bản khi không vượt ngưỡng

+
+
+ + handleRateLimiterChange('feeIncrementBps', e.target.value)} + className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-red-500 text-sm sm:text-base" + min="0" + max={9900 - formData.rateLimiterParam.baseFeeBps} + required + /> +

Phí tăng thêm khi vượt ngưỡng

+
+
+ +
+
+ + handleRateLimiterChange('referenceAmount', e.target.value)} + className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-red-500 text-sm sm:text-base" + min="0" + required /> +

Ngưỡng kích hoạt fee increment

+
+
+ + handleRateLimiterChange('maxLimiterDuration', e.target.value)} + className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-red-500 text-sm sm:text-base" + min="0" + required + /> +

Thời gian tối đa của limiter

)} - {/* Fee Information Cards */} + {/* Information Cards */}

Fee Structure

- Fees are charged on transactions and help maintain liquidity. - Consider market conditions when setting fee rates. + Phí được tính trên các giao dịch và giúp duy trì tính thanh khoản. + Cân nhắc điều kiện thị trường khi thiết lập mức phí.

-

Scheduler Benefits

+

+ {isSchedulerMode ? "Scheduler Benefits" : "Rate Limiter Benefits"} +

- Fee scheduling allows gradual fee reduction over time, - encouraging early adoption while maintaining sustainability. + {isSchedulerMode + ? "Fee scheduling cho phép giảm phí dần theo thời gian, khuyến khích early adoption trong khi duy trì tính bền vững." + : "Rate limiter giúp kiểm soát khối lượng giao dịch lớn bằng cách tăng phí khi vượt ngưỡng tham chiếu." + }

{/* Fee Preview */} - {isSchedulerMode && ( + {feePreview && (
-

Fee Schedule Preview

+

Fee Preview

-
- Starting Fee: - {feePreview.startingFeePercent}% -
-
- Ending Fee: - {feePreview.endingFeePercent}% -
-
- Duration: - {formData.feeSchedulerParam.totalDuration} days -
-
- Periods: - {formData.feeSchedulerParam.numberOfPeriod} -
+ {isSchedulerMode && 'startingFeePercent' in feePreview && ( + <> +
+ Starting Fee: + {feePreview.startingFeePercent}% +
+
+ Ending Fee: + {feePreview.endingFeePercent}% +
+
+ Duration: + {formData.feeSchedulerParam?.totalDuration} +
+
+ Periods: + {formData.feeSchedulerParam?.numberOfPeriod} +
+ + )} + {isRateLimiterMode && 'baseFeePercent' in feePreview && ( + <> +
+ Base Fee: + {feePreview.baseFeePercent}% +
+
+ Max Fee (with increment): + {feePreview.maxFeePercent}% +
+
+ Reference Amount: + {formData.rateLimiterParam?.referenceAmount.toLocaleString()} +
+ + )}
)} @@ -257,7 +426,7 @@ export default function FeeConfig({ {/* Action Buttons */}
- - + + + handleQuoteTypeChange('usdc')} + className="cursor-pointer" + > +
+ {TOKEN_QUOTE_OPTIONS.usdc.label} + {TOKEN_QUOTE_OPTIONS.usdc.label} +
+
+ handleQuoteTypeChange('usdt')} + className="cursor-pointer" + > +
+ {TOKEN_QUOTE_OPTIONS.usdt.label} + {TOKEN_QUOTE_OPTIONS.usdt.label} +
+
+ handleQuoteTypeChange('wsol')} + className="cursor-pointer" + > +
+ {TOKEN_QUOTE_OPTIONS.wsol.label} + {TOKEN_QUOTE_OPTIONS.wsol.label} +
+
+ handleQuoteTypeChange('custom')} + className="cursor-pointer" + > + {TOKEN_QUOTE_OPTIONS.custom.label} + +
+ + + {formData.tokenQuoteType === 'custom' && ( + handleInputChange('tokenQuoteAddress', e.target.value)} + className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-red-500 text-sm sm:text-base mt-2" + /> + )} +
diff --git a/app/src/components/create-token/custom/vesting.tsx b/app/src/components/create-token/custom/vesting.tsx index 19374dc..0b0aece 100644 --- a/app/src/components/create-token/custom/vesting.tsx +++ b/app/src/components/create-token/custom/vesting.tsx @@ -2,6 +2,7 @@ import React, { useState, useMemo, useCallback } from 'react'; import { Progress } from '@/components/ui/progress'; +import { InfoTooltip, DBC_TOOLTIPS } from '@/components/ui/info-tooltip'; interface VestingProps { onNext: (data: VestingData) => void; @@ -29,11 +30,11 @@ export default function Vesting({ initialData }: VestingProps) { const [formData, setFormData] = useState({ - totalLockedVestingAmount: initialData?.totalLockedVestingAmount || 20000, - numberOfVestingPeriod: initialData?.numberOfVestingPeriod || 9, - cliffUnlockAmount: initialData?.cliffUnlockAmount || 5000, - totalVestingDuration: initialData?.totalVestingDuration || 9*30*24*3600, - cliffDurationFromMigrationTime: initialData?.cliffDurationFromMigrationTime || 3*30*24*3600, + totalLockedVestingAmount: initialData?.totalLockedVestingAmount || 0, + numberOfVestingPeriod: initialData?.numberOfVestingPeriod || 0, + cliffUnlockAmount: initialData?.cliffUnlockAmount || 0, + totalVestingDuration: initialData?.totalVestingDuration || 0, + cliffDurationFromMigrationTime: initialData?.cliffDurationFromMigrationTime || 0, }); const progressPercentage = useMemo(() => @@ -112,7 +113,11 @@ export default function Vesting({
+ + + {children || ( + + )} + + + {title &&

{title}

} +

{content}

+
+
+ + ); +} + +// DBC Config Tooltips from Meteora Docs +export const DBC_TOOLTIPS = { + buildCurveMode: { + title: "Build Curve Mode", + modes: { + "0": { + label: "Build Curve", + description: "Useful when you want to create a curve configuration with specific migrationQuoteThreshold and percentageSupplyOnMigration. The percentage specifies the ratio of total token supply that will be migrated to the LP pool after graduation." + }, + "1": { + label: "Market Cap Based", + description: "Useful when you want to create a curve configuration with specific initial token price and migration price. Use this when you have defined initial and migration market cap targets for your token." + }, + "2": { + label: "Two Segments", + description: "Creates a dual constant product curve structure. Requires initialMarketCap, migrationMarketCap and percentageSupplyOnMigration to define the two-segment bonding curve." + }, + "3": { + label: "Liquidity Weights", + description: "Useful when you want to create a curve configuration with unique price action (flat, exponential, etc.). Liquidity weights work as exponents controlling the thickness of segments, allowing customization of price dynamics across curve segments." + } + } + }, + percentageSupplyOnMigration: "Percentage of total token supply that will be migrated to the liquidity pool after graduation. Value from 0-100%.", + migrationQuoteThreshold: "Minimum amount of quote tokens required to qualify for migration. Set minimum 750 USD for automatic migration via migration keepers.", + initialMarketCap: "Market cap of DBC token pool when pool is created, specified in quoteMint (not lamports).", + migrationMarketCap: "Market cap of DBC token pool when pool graduates, specified in quoteMint (not lamports).", + liquidityWeights: "Array of 16 liquidity weights for each liquidity segment in the curve. Weights work as exponents to control price action.", + migrationOption: { + title: "Migration Option", + options: { + "0": "DAMM v1 - Pool will be migrated to DAMM v1 pool. Post-graduation pools use Output Token collection mode.", + "1": "DAMM v2 - Pool will be migrated to DAMM v2 pool. Uses Quote Token collection; dynamic fees add 20% to base fees." + } + }, + migrationFeeOption: { + title: "Migration Fee Option", + description: "Predefined LP fee tiers from 0.25% to 6%. Option 6 (Customizable) is only available if migrationOption is set to DAMM v2." + }, + dynamicFeeEnabled: "If true, dynamic fee will add 20% of minimum base fee to the total fee.", + activationType: { + title: "Activation Type", + options: { + "0": "Slot - Pool time is measured in Slots (1 slot = 400ms)", + "1": "Timestamp - Pool time is measured in Timestamps (seconds)" + } + }, + collectFeeMode: { + title: "Collect Fee Mode", + options: { + "0": "Quote Token - Pre-graduation fees are collected as Quote Token", + "1": "Output Token - Pre-graduation fees are collected as Output Token" + } + }, + tokenType: { + title: "Token Type", + options: { + "0": "SPL - Standard SPL token", + "1": "Token 2022 - Token following the new Token-2022 standard" + } + }, + baseFeeMode: { + title: "Base Fee Mode", + modes: { + "0": "Linear Fee Scheduler - Fees decrease linearly over time", + "1": "Exponential Fee Scheduler - Fees decrease exponentially", + "2": "Rate Limiter - Limits transaction rate with dynamically increasing fees" + } + }, + feeScheduler: { + startingFeeBps: "Starting fee in basis points (100 bps = 1%). Maximum 99% (9900 bps).", + endingFeeBps: "Ending fee in basis points. Minimum 0.01% (1 bps).", + numberOfPeriod: "Number of periods for fees to decrease from starting to ending.", + totalDuration: "Total duration (if activationType=0: duration/0.4, if =1: duration in seconds)" + }, + rateLimiter: { + baseFeeBps: "Base fee in basis points. Maximum 99% (9900 bps).", + feeIncrementBps: "Fee increment when exceeding reference amount. Maximum = 9900 bps - baseFeeBps.", + referenceAmount: "Reference amount (not lamports) to trigger fee increment.", + maxLimiterDuration: "Maximum limiter duration (if activationType=0: duration/0.4, if =1: duration)" + }, + vesting: { + totalLockedVestingAmount: "Total amount of baseMint tokens locked in vesting. Only starts after pool has migrated.", + numberOfVestingPeriod: "Total number of vesting periods.", + cliffUnlockAmount: "Amount of tokens unlocked immediately after cliff period (in lamports).", + totalVestingDuration: "Total vesting duration (in seconds).", + cliffDurationFromMigrationTime: "Cliff time from migration (in seconds). No tokens are unlocked during this period." + }, + lpDistribution: { + partnerLpPercentage: "Percentage of unlockable LP tokens for partner. Can be withdrawn after pool migrates.", + creatorLpPercentage: "Percentage of unlockable LP tokens for creator. Can be withdrawn after pool migrates.", + partnerLockedLpPercentage: "Percentage of permanently locked LP tokens for partner. Cannot be withdrawn after migration.", + creatorLockedLpPercentage: "Percentage of permanently locked LP tokens for creator. Cannot be withdrawn after migration.", + creatorTradingFeePercentage: "Percentage of bonding curve trading fees shared to creator (0% to 100%). 0% means all trading fees go to partner.", + leftover: "Amount of leftover tokens in bonding curve (can be claimed after pool migrates).", + note: "Total of 4 LP percentages (partner + creator + partnerLocked + creatorLocked) must equal 100%." + }, + migrationFee: { + feePercentage: "Percentage fee taken from migration quote threshold when pool migrates (0% to 50%).", + creatorFeePercentage: "Percentage of migrationFee.feePercentage that creator can claim (0% to 100%)." + }, + migratedPoolFee: { + description: "Only configure when migrationOption = DAMM v2 (1) and migrationFeeOption = Customizable (6).", + collectFeeMode: "0: Quote Token, 1: Output Token", + dynamicFee: "0: Disabled, 1: Enabled", + poolFeeBps: "Pool fee in basis points. Minimum 10, maximum 1000 bps." + }, + tokenUpdateAuthority: { + title: "Token Update Authority", + options: { + "0": "Creator Update Authority - Creator controls metadata updates", + "1": "Immutable - Metadata is frozen; mint authority is revoked", + "2": "Partner Update Authority - Partner controls metadata", + "3": "Creator Update & Mint Authority - Creator controls metadata and minting", + "4": "Partner Update & Mint Authority - Partner controls metadata and minting" + } + }, + leftoverReceiver: "Wallet address that will receive leftover tokens from bonding curve after migration.", + feeClaimer: "Wallet address that will receive collected fees." +}; diff --git a/app/src/types/token.ts b/app/src/types/token.ts index 0a189a9..286c674 100644 --- a/app/src/types/token.ts +++ b/app/src/types/token.ts @@ -25,30 +25,53 @@ export const CustomMintSchema = z.object({ totalTokenSupply: z.number().positive(), tokenBaseDecimal: z.number().min(0), tokenQuoteDecimal: z.number().min(0), + tokenQuoteAddress: z.string().optional(), + tags: z.array(z.string()).optional(), }), // --- DBC CONFIGURATION --- dbcConfig: z.object({ buildCurveMode: z.enum(["0", "1", "2", "3"]), - percentageSupplyOnMigration: z.number().min(0).max(100), - migrationQuoteThreshold: z.number().positive(), + // Mode 0: buildCurve + percentageSupplyOnMigration: z.number().min(0).max(100).optional(), + migrationQuoteThreshold: z.number().positive().optional(), + // Mode 1, 2, 3: Market Cap Based + initialMarketCap: z.number().positive().optional(), + migrationMarketCap: z.number().positive().optional(), + // Mode 3: Liquidity Weights + liquidityWeights: z.array(z.number()).length(16).optional(), + // General settings migrationOption: z.enum(["0", "1"]), dynamicFeeEnabled: z.boolean(), activationType: z.enum(["0", "1"]), collectFeeMode: z.enum(["0", "1"]), - migrationFeeOption: z.enum(["0", "1", "2", "3", "4", "5"]), + migrationFeeOption: z.enum(["0", "1", "2", "3", "4", "5", "6"]), tokenType: z.enum(["0", "1"]), + // Migrated Pool Fee (only for DAMM v2 + Customizable) + migratedPoolFee: z.object({ + collectFeeMode: z.enum(["0", "1"]), + dynamicFee: z.enum(["0", "1"]), + poolFeeBps: z.number().min(10).max(1000), + }).optional(), }), // --- FEE CONFIGURATION --- baseFeeParams: z.object({ baseFeeMode: z.enum(["0", "1", "2"]), + // Mode 0, 1: Fee Scheduler feeSchedulerParam: z.object({ startingFeeBps: z.number().min(0), endingFeeBps: z.number().min(0), numberOfPeriod: z.number(), totalDuration: z.number(), - }), + }).optional(), + // Mode 2: Rate Limiter + rateLimiterParam: z.object({ + baseFeeBps: z.number().min(0).max(9900), + feeIncrementBps: z.number().min(0), + referenceAmount: z.number().min(0), + maxLimiterDuration: z.number().min(0), + }).optional(), }), // --- VESTING CONFIGURATION --- @@ -66,8 +89,22 @@ export const CustomMintSchema = z.object({ creatorLpPercentage: z.number().min(0).max(100), partnerLockedLpPercentage: z.number().min(0).max(100), creatorLockedLpPercentage: z.number().min(0).max(100), + creatorTradingFeePercentage: z.number().min(0).max(100), + leftover: z.number().min(0), + // Migration Fee (optional) + migrationFee: z.object({ + feePercentage: z.number().min(0).max(50), + creatorFeePercentage: z.number().min(0).max(100), + }).optional(), }), + // --- MIGRATED POOL FEE (only for DAMM v2 + Custom fee) --- + migratedPoolFee: z.object({ + collectFeeMode: z.enum(["0", "1"]), + dynamicFee: z.enum(["0", "1"]), + poolFeeBps: z.number().min(10).max(1000), + }).optional(), + // --- AUTHORITY CONFIGURATION --- authority: z.object({ tokenUpdateAuthority: z.enum(["0", "1", "2", "3", "4"]),