Skip to main content
Call lockPosition on the FlashnetClient with a pool ID, a lockUntilTimestamp string, and, for V3 positions, the tick range.

Signature

await client.lockPosition(
  poolId: string,
  lockUntilTimestamp: string,     // Unix seconds; "0" = indefinite
  opts?: {
    tickLower?: number;           // V3 only
    tickUpper?: number;           // V3 only
  }
): Promise<LockPositionResponse>;
The timestamp must parse as a non-negative integer at or below "4102444800" (2100-01-01 UTC). Pass "0" for an indefinite lock.

Create a bounded lock

V2

// Lock a V2 LP position for 30 days
const thirtyDays = Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60;

const response = await client.lockPosition(
  poolId,
  String(thirtyDays)
);

console.log("Accepted:", response.accepted);
console.log("Expires at:", response.lockUntilTimestamp);
console.log("Indefinite:", response.isIndefinite);   // false
Omit tickLower and tickUpper for V2 positions. The server scopes the lock to the entire LP share owned by the caller’s public key in that pool.

V3

// Lock a V3 position at a specific tick range
const response = await client.lockPosition(
  poolId,
  "1793836800",   // 2026-11-04 UTC
  { tickLower: -69080, tickUpper: -66850 }
);
Both tickLower and tickUpper are required together for V3. The tick pair must match an existing position owned by the caller. Supplying only one of the two is rejected.

Create an indefinite lock

// V2
await client.lockPosition(poolId, "0");

// V3
await client.lockPosition(poolId, "0", { tickLower, tickUpper });
An indefinite lock cannot be converted to a bounded duration. Use "0" only when the hold has no planned release.

Extend an existing lock

Call lockPosition again with a later timestamp (or "0"). The server updates the record in place.
const now = Math.floor(Date.now() / 1000);

// Initial lock: 30 days
await client.lockPosition(poolId, String(now + 30 * 86400));

// Later: extend to 90 days
await client.lockPosition(poolId, String(now + 90 * 86400));

Rules on modification

  • A new bounded timestamp must be greater than or equal to the existing one.
  • A bounded lock can be converted to indefinite by passing "0".
  • An indefinite lock ("0") cannot be converted back to bounded.
  • Any request that would shorten the lock is rejected without state changes.

Error handling

The SDK throws when the server rejects a request. Common rejections:
  • Position not found. The (poolId, owner, tickLower, tickUpper) tuple does not match a live position owned by the caller.
  • Shortening attempted. The requested timestamp is earlier than the existing lock.
  • Invalid timestamp. The string does not parse as a non-negative integer at or below 4102444800.
import { isFlashnetError } from "@flashnet/sdk";

try {
  await client.lockPosition(poolId, "1793836800", { tickLower, tickUpper });
} catch (error) {
  if (isFlashnetError(error)) {
    console.error(error.errorCode, error.userMessage);
  }
  throw error;
}

Next steps