Liquidity Positions

This section introduces liquidity positions in Storyhunt V3

Introduction

This section introduces liquidity positions in Storyhunt V3 and provides an overview of the SDK classes and contracts used to interact with the protocol. The focus is on the Position and NonfungiblePositionManager classes, as well as the NonfungiblePositionManager contract.

At the end, you will understand the core classes for interacting with liquidity positions and learn how to fetch positions from the NonfungiblePositionManager contract.

Prerequisites

To understand liquidity positions, itโ€™s essential to grasp the concept of concentrated liquidity, ticks, and how they influence liquidity provisioning in Storyhunt V3.

Concentrated Liquidity

Storyhunt V3 pools use concentrated liquidity, allowing liquidity providers to focus their liquidity in specific price ranges. This approach increases capital efficiency compared to traditional models by enabling larger trades with less price impact. Liquidity providers can specify the price range for their liquidity.

Ticks

Ticks define the boundaries of discrete price ranges. Each tick represents a price change of 0.01% from the previous tick. Pools have a tickSpacing value that determines which ticks are usable, based on the poolโ€™s fee tier. Higher fees result in larger tick spacings.

1.0001200=1.0202 1.0001^{200} = 1.0202 or 2.022.02%

For example, a pool with a 1% fee and a tickSpacing of 200 means the price difference between initializable ticks is approximately 2.02%.

Liquidity Positions

When liquidity is added to a pool, a liquidity position is created. This position includes the amount of liquidity and the start and end ticks (price range) of the position. Positions outside the poolโ€™s current price range result in single-sided liquidity, where only one token is added to the pool.

Position Class

The Position class is used to create local representations of on-chain positions and to generate calldata for on-chain transactions such as minting or modifying a position.

Constructing a Position

Using the Constructor:

import { Pool, Position } from '@storyhunt/v3-sdk';
import JSBI from 'jsbi';

const pool = new Pool(...);
const tickLower = -100;
const tickUpper = 200;
const liquidity = JSBI.BigInt('1000000000000000000');

const position = new Position({
  pool,
  liquidity,
  tickLower,
  tickUpper,
});

Using fromAmounts():

import { BigIntish } from '@storyhunt/sdk-core';

const amount0 = '1000000000000000000';
const amount1 = JSBI.BigInt('1000000000000000000');
const useFullPrecision = true;

const position = Position.fromAmounts({
  pool,
  tickLower,
  tickUpper,
  amount0,
  amount1,
  useFullPrecision,
});

Using fromAmount0() or fromAmount1():

const amount0 = '1000000000000000000';
const singleSidePositionToken0 = Position.fromAmount0({
  pool,
  tickLower,
  tickUpper,
  amount0,
  useFullPrecision,
});

const amount1 = 100000000;
const singleSidePositionToken1 = Position.fromAmount1({
  pool,
  tickLower,
  tickUpper,
  amount1,
  useFullPrecision,
});

The tick values must match the poolโ€™s initializable ticks, and the wallet must hold sufficient tokens to cover the position.

NonfungiblePositionManager

The NonfungiblePositionManager class is primarily used to create calldata for functions on the NonfungiblePositionManager contract.

Creating a Position

To create a position in a pool, use the mint function on the contract. The SDK class provides the addCallParameters method to generate the necessary calldata:

import { MintOptions, NonfungiblePositionManager } from '@storyhunt/v3-sdk';

const mintOptions: MintOptions = {
  recipient: address,
  deadline: Math.floor(Date.now() / 1000) + 60 * 20,
  slippageTolerance: new Percent(50, 10_000),
};

const { calldata, value } = NonfungiblePositionManager.addCallParameters(
  positionToMint,
  mintOptions
);

Modifying a Position

To adjust a position, use the removeCallParameters for decreasing liquidity or addCallParameters for increasing liquidity:

const { calldata, value } = NonfungiblePositionManager.removeCallParameters(
  currentPosition,
  removeLiquidityOptions
);

Collecting Fees

To collect fees accrued by a position, use the collectCallParameters method:

const { calldata, value } =
  NonfungiblePositionManager.collectCallParameters(collectOptions);

Next Steps

Now that you understand the key classes and contracts for managing liquidity positions, you can proceed to explore advanced functionality such as minting new positions or modifying existing ones.