Position Management
Get user positions
const positions: ClmmPosition[] = positionManager.getUserPositions('0xaddress');
Get position reward
const positions: ClmmPosition[] = positionManager.getUserPositions('0xaddress');
const positionWithReward: ClmmPosition[] = positionManager.getPositionReward(positions);
Open/Increase a Position
import { ClmmPosition, CoinAmount, Percent, BN } from '@flowx-finance/sdk';
import { TransactionResult } from '@mysten/sui/transactions';
// Method 1: Create position with specific liquidity amount
const tickLower = -3000; // Lower price tick (must be divisible by tick spacing: 60 for MEDIUM fee)
const tickUpper = 3000; // Upper price tick (must be divisible by tick spacing: 60 for MEDIUM fee)
const liquidity = new BN(1000);
const position = new ClmmPosition({
objectId: '0x...', // Optional: Your position object id if you want increase exist position
owner: '0x...', // Your address
pool: pool,
tickLower,
tickUpper,
liquidity,
coinsOwedX: 0,
coinsOwedY: 0,
feeGrowthInsideXLast: 0,
feeGrowthInsideYLast: 0,
rewardInfos: [],
});
// Method 2: Create position with specific token amounts
const amountX = new BN('1000000000'); // 1 SUI (9 decimals)
const amountY = new BN('1000000'); // 1 USDC (6 decimals)
const positionFromAmounts = ClmmPosition.fromAmounts({
objectId: '0x...', // Optional: Your position object id if you want increase exist position
owner: '0x...', // Your address
pool: pool,
tickLower: -3000,
tickUpper: 3000,
amountX: amountX,
amountY: amountY,
useFullPrecision: true, // Use full precision for liquidity calculation
});
// Method 3: Create position with only amountX (single-sided liquidity)
const positionOnlyX = ClmmPosition.fromAmountX({
objectId: '0x...', // Optional: Your position object id if you want increase exist position
owner: '0x...', // Your address
pool: pool,
tickLower: -3000,
tickUpper: 3000,
amountX: amountX, // Only provide amountX
// amountY not provided - will be calculated based on current price
useFullPrecision: true,
});
// Method 4: Create position with only amountY (single-sided liquidity)
const positionOnlyY = ClmmPosition.fromAmountY({
objectId: '0x...', // Optional: Your position object id if you want increase exist position
owner: '0x...', // Your address
pool: pool,
tickLower: -3000,
tickUpper: 3000,
amountY: amountY, // Only provide amountY
// amountX not provided - will be calculated based on current price
useFullPrecision: true,
});
// Create position with liquidity
const options = {
slippageTolerance: new Percent(1, 100), // 1% slippage
deadline: Date.now() + 3600 * 1000, // 1 hour from now
createPosition: true,
};
const tx = new Transaction();
const createdPosition = positionManager.tx(tx).increaseLiquidity(position, options);
tx.transferObjects([createdPosition], recipient);
Decrease Liquidity
// Define MaxU64 constant for convenience
const MaxU64 = new BN('18446744073709551615');
// Example 1: Remove 50% of liquidity
const positionId = '0x...'; // Position object ID
const position = await positionManager.getPosition(positionId);
const liquidityToRemove = position.liquidity.div(new BN(2));
const positionWillBeDecreased = new ClmmPosition({
owner: position.owner,
pool: position.pool,
tickLower: position.tickLower,
tickUpper: position.tickUpper,
liquidity: liquidityToRemove,
coinsOwedX: 0,
coinsOwedY: 0,
feeGrowthInsideXLast: 0,
feeGrowthInsideYLast: 0,
rewardInfos: [],
});
const burnAmounts = {
amountX: positionWillBeDecreased.amountX,
amountY: positionWillBeDecreased.amountY,
};
const decreaseOptions = {
slippageTolerance: new Percent(1, 100),
deadline: Date.now() + 3600 * 1000, // 1 hour from now
collectOptions: {
expectedCoinOwedX: CoinAmount.fromRawAmount(coinX, burnAmounts.amountX),
expectedCoinOwedY: CoinAmount.fromRawAmount(coinY, burnAmounts.amountY),
},
};
const tx = new Transaction();
positionManager.tx(tx).decreaseLiquidity(position, decreaseOptions);
// Example 2: Remove all liquidity and close position
const positionToClose = await positionManager.getPosition(positionId);
const closeOptions = {
slippageTolerance: new Percent(1, 100),
deadline: Date.now() + 3600 * 1000, // 1 hour from now
collectOptions: {
// Use MaxU64 to ensure we collect all available fees regardless of fee growth during processing
expectedCoinOwedX: CoinAmount.fromRawAmount(coinX, MaxU64),
expectedCoinOwedY: CoinAmount.fromRawAmount(coinY, MaxU64),
},
};
const closeTx = new Transaction();
positionManager.tx(closeTx).decreaseLiquidity(positionToClose, closeOptions);
// Get all available rewards before closing
const rewards = await positionToClose.getRewards();
// Collect all available rewards
for (let i = 0; i < rewards.length; i++) {
if (rewards[i].gt(new BN(0))) {
const collectRewardOptions = {
expectedRewardOwed: CoinAmount.fromRawAmount(
positionToClose.pool.poolRewards[i].coin,
MaxU64 // Use MaxU64 for rewards as well
),
recipient: '0x...', // Optional recipient
};
positionManager.collectPoolReward(positionToClose, i, collectRewardOptions);
}
}
// Close the position (burn the NFT)
positionManager.closePosition(positionToClose, closeTx);
Collecting Fees and Rewards
// Define MaxU64 constant for convenience
const MaxU64 = new BN('18446744073709551615');
// Example 1: Collect accumulated fees only
const positionId = '0x...'; // Position object ID
const position = await positionManager.getPosition(positionId);
// Get current fees
const fees = await position.getFees();
if (fees.amountX.gt(new BN(0)) || fees.amountY.gt(new BN(0))) {
const collectFeeOptions = {
expectedCoinOwedX: CoinAmount.fromRawAmount(coinX, MaxU64),
expectedCoinOwedY: CoinAmount.fromRawAmount(coinY, MaxU64),
recipient: '0x...', // Optional recipient
};
const tx = new Transaction();
positionManager.tx(tx);
// Collect returns the collected coin objects
const [collectedX, collectedY] = positionManager.collect(position, collectFeeOptions) as TransactionResult;
// Transfer to recipient if not specified in collectFeeOptions
if (!collectFeeOptions.recipient) {
tx.transferObjects([collectedX, collectedY], position.owner);
}
}
// Example 2: Collect specific reward tokens
const rewards = await position.getRewards();
for (let i = 0; i < rewards.length; i++) {
if (rewards[i].gt(new BN(0))) {
const collectRewardOptions = {
expectedRewardOwed: CoinAmount.fromRawAmount(position.pool.poolRewards[i].coin, MaxU64),
recipient: '0x...', // Optional recipient
};
const tx = new Transaction();
positionManager.tx(tx);
positionManager.collectPoolReward(position, i, collectRewardOptions);
}
}
Rebalance example
const tx = new Transaction();
const rebalancer = new Rebalancer({
network: "mainnet",
});
const newPosition = await rebalancer.rebalance(
clmmPosition,
tickLower,
tickUpper,
{
slippageTolerance: 1000,
priceImpactPercentThreshold: -5000,
minZapAmounts: {
amountX: 1000,
amountY: 1000,
},
},
)(tx);
tx.transferObjects([newPosition], position.owner);
Last updated
Was this helpful?