Ver Fonte

Fix error 3007: disable shouldClaimAndClose, use separate close step

shouldClaimAndClose=true appends claimFee/claimReward/closePositionIfEmpty
instructions to the removeLiquidity transaction. On Token-2022 pools, these
fail with error 3007 (AccountOwnedByWrongProgram) due to token program
mismatch in the fee/reward claim accounts.

Fix: always set shouldClaimAndClose=false, and handle close position as a
separate step via copyClosePosition (which already handles already-closed
positions gracefully via getAccountInfo check).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
lushdog@outlook.com há 3 semanas atrás
pai
commit
bf7aa6601f
2 ficheiros alterados com 18 adições e 14 exclusões
  1. 4 1
      src/lib/meteora/dlmm-client.ts
  2. 14 13
      src/worker/executor.ts

+ 4 - 1
src/lib/meteora/dlmm-client.ts

@@ -135,7 +135,10 @@ export async function copyRemoveLiquidity(
 		fromBinId: Math.min(...binIds),
 		toBinId: Math.max(...binIds),
 		bps: new BN(bpsToRemove),
-		shouldClaimAndClose: bpsToRemove >= 10000,
+		// Never use shouldClaimAndClose — its claim fee/reward instructions
+		// can fail with error 3007 (AccountOwnedByWrongProgram) on Token-2022
+		// pools. Close is handled separately by copyClosePosition instead.
+		shouldClaimAndClose: false,
 	})
 
 	let lastSignature = ''

+ 14 - 13
src/worker/executor.ts

@@ -311,12 +311,10 @@ export class CopyExecutor {
 		)
 
 		try {
-			// Remove all liquidity with shouldClaimAndClose=true.
-			// This removes liquidity, claims fees, AND closes the position account
-			// in one step — no separate closePosition call needed.
-			let followerTx: string
+			// Step 1: Remove all liquidity (without shouldClaimAndClose to avoid
+			// error 3007 on Token-2022 pools)
 			try {
-				followerTx = await copyRemoveLiquidity(
+				await copyRemoveLiquidity(
 					this.connection,
 					this.follower,
 					new PublicKey(followerInfo.positionAddress),
@@ -325,18 +323,21 @@ export class CopyExecutor {
 					this.settings
 				)
 			} catch (removeErr) {
-				// If remove fails (e.g. position already empty), try direct close
+				// Liquidity might already be removed (e.g. after a failed rebalance)
 				console.log(
-					`[Executor] Remove liquidity failed (${removeErr}), trying direct close...`
-				)
-				followerTx = await copyClosePosition(
-					this.connection,
-					this.follower,
-					new PublicKey(followerInfo.positionAddress),
-					new PublicKey(followerInfo.lbPairAddress)
+					`[Executor] Remove liquidity failed (${removeErr}), proceeding to close...`
 				)
 			}
 
+			// Step 2: Close the empty position account (reclaims rent)
+			// copyClosePosition handles already-closed positions gracefully
+			const followerTx = await copyClosePosition(
+				this.connection,
+				this.follower,
+				new PublicKey(followerInfo.positionAddress),
+				new PublicKey(followerInfo.lbPairAddress)
+			)
+
 			await closeFollowerPosition(followerInfo.positionAddress)
 			await updateCopyTradeStatus(copyTrade.id, 'SUCCESS', {
 				followerTxSignature: followerTx,