|
@@ -6,16 +6,21 @@ import bs58 from 'bs58'
|
|
|
import { chain } from '@/lib/config'
|
|
import { chain } from '@/lib/config'
|
|
|
import { TickMath } from '@/lib/byreal-clmm-sdk/src/instructions/utils/tickMath'
|
|
import { TickMath } from '@/lib/byreal-clmm-sdk/src/instructions/utils/tickMath'
|
|
|
|
|
|
|
|
-export async function POST(request: NextRequest) {
|
|
|
|
|
|
|
+async function copyLPPosition(
|
|
|
|
|
+ request: NextRequest,
|
|
|
|
|
+ attempt: number = 1
|
|
|
|
|
+): Promise<NextResponse> {
|
|
|
|
|
+ const body = await request.json()
|
|
|
|
|
+ const {
|
|
|
|
|
+ positionAddress,
|
|
|
|
|
+ maxUsdValue,
|
|
|
|
|
+ nftMintAddress,
|
|
|
|
|
+ priceLower: priceLowerPct = 0,
|
|
|
|
|
+ priceUpper: priceUpperPct = 0,
|
|
|
|
|
+ } = body
|
|
|
|
|
+
|
|
|
try {
|
|
try {
|
|
|
- const body = await request.json()
|
|
|
|
|
- const {
|
|
|
|
|
- positionAddress,
|
|
|
|
|
- maxUsdValue,
|
|
|
|
|
- nftMintAddress,
|
|
|
|
|
- priceLower: priceLowerPct = 0,
|
|
|
|
|
- priceUpper: priceUpperPct = 0,
|
|
|
|
|
- } = body
|
|
|
|
|
|
|
+ // 原有的主要逻辑会放在这里
|
|
|
|
|
|
|
|
if (!positionAddress) {
|
|
if (!positionAddress) {
|
|
|
return NextResponse.json(
|
|
return NextResponse.json(
|
|
@@ -52,6 +57,29 @@ export async function POST(request: NextRequest) {
|
|
|
const poolInfo = rawPoolInfo
|
|
const poolInfo = rawPoolInfo
|
|
|
const tickSpacing = poolInfo.tickSpacing
|
|
const tickSpacing = poolInfo.tickSpacing
|
|
|
|
|
|
|
|
|
|
+ // 检查 LP 是否在区间内
|
|
|
|
|
+ const currentTick = TickMath.getTickWithPriceAndTickspacing(
|
|
|
|
|
+ new Decimal(poolInfo.currentPrice),
|
|
|
|
|
+ tickSpacing,
|
|
|
|
|
+ poolInfo.mintDecimalsA,
|
|
|
|
|
+ poolInfo.mintDecimalsB
|
|
|
|
|
+ )
|
|
|
|
|
+ const positionTickLower = positionInfo.rawPositionInfo.tickLower
|
|
|
|
|
+ const positionTickUpper = positionInfo.rawPositionInfo.tickUpper
|
|
|
|
|
+
|
|
|
|
|
+ if (currentTick < positionTickLower || currentTick > positionTickUpper) {
|
|
|
|
|
+ return NextResponse.json(
|
|
|
|
|
+ {
|
|
|
|
|
+ error:
|
|
|
|
|
+ 'Position is out of range (current price is outside the position tick range)',
|
|
|
|
|
+ currentTick,
|
|
|
|
|
+ tickLower: positionTickLower,
|
|
|
|
|
+ tickUpper: positionTickUpper,
|
|
|
|
|
+ },
|
|
|
|
|
+ { status: 400 }
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// 使用 currentPrice (A/B 价格) 来计算 token 的 USD 价格
|
|
// 使用 currentPrice (A/B 价格) 来计算 token 的 USD 价格
|
|
|
// currentPrice 是 tokenA / tokenB 的比率
|
|
// currentPrice 是 tokenA / tokenB 的比率
|
|
|
const currentPrice = poolInfo.currentPrice
|
|
const currentPrice = poolInfo.currentPrice
|
|
@@ -503,9 +531,27 @@ export async function POST(request: NextRequest) {
|
|
|
},
|
|
},
|
|
|
})
|
|
})
|
|
|
} catch (error: unknown) {
|
|
} catch (error: unknown) {
|
|
|
- console.error('LP copy error:', error)
|
|
|
|
|
|
|
+ console.error(`LP copy error (attempt ${attempt}):`, error)
|
|
|
const errorMessage =
|
|
const errorMessage =
|
|
|
error instanceof Error ? error.message : 'Failed to copy LP position'
|
|
error instanceof Error ? error.message : 'Failed to copy LP position'
|
|
|
|
|
+
|
|
|
|
|
+ // 如果错误包含 "Price slippage check",最多重试 3 次
|
|
|
|
|
+ if (errorMessage.includes('Price slippage check') && attempt < 3) {
|
|
|
|
|
+ console.log(`Retrying LP copy (attempt ${attempt + 1})...`)
|
|
|
|
|
+ await new Promise((resolve) => setTimeout(resolve, 1000 * attempt)) // 延迟重试,逐渐增加
|
|
|
|
|
+ return copyLPPosition(request, attempt + 1)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 如果错误包含 "insufficient funds",返回友好的余额不足提示
|
|
|
|
|
+ if (errorMessage.includes('insufficient funds')) {
|
|
|
|
|
+ return NextResponse.json({ error: '余额不足' }, { status: 400 })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
return NextResponse.json({ error: errorMessage }, { status: 500 })
|
|
return NextResponse.json({ error: errorMessage }, { status: 500 })
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+// 主入口函数
|
|
|
|
|
+export async function POST(request: NextRequest) {
|
|
|
|
|
+ return copyLPPosition(request, 1)
|
|
|
|
|
+}
|