Minting a Position
This section explains how to create (or mint) a liquidity position on the Storyhunt V3 protocol.
Introduction
This section explains how to create (or mint) a liquidity position on the Storyhunt V3 protocol. In Storyhunt V3, liquidity positions are represented using non-fungible tokens. This guide demonstrates minting a liquidity position for the USDC - DAI pair, including transferring token approvals, creating a pool instance, calculating the position, and executing the minting transaction.
Giving Approval to Transfer Tokens
The first step is to approve the protocolβs NonfungiblePositionManager
contract to transfer your tokens. Since both USDC and DAI are ERC20 tokens, their contracts need approval to transfer funds on your behalf:
import { ethers, BigNumber } from 'ethers';
async function getTokenTransferApproval(address: string, amount: BigNumber) {
const provider = new ethers.providers.JsonRpcProvider(rpcUrl);
const tokenContract = new ethers.Contract(
address,
ERC20_ABI,
provider
);
return tokenContract.approve(
NONFUNGIBLE_POSITION_MANAGER_CONTRACT_ADDRESS,
amount
);
}
const token0Approval = await getTokenTransferApproval(token0Address, amount0);
const token1Approval = await getTokenTransferApproval(token1Address, amount1);
Creating a Pool Instance
After approving token transfers, gather the required pool data to instantiate the Pool
class. Compute the pool address using the unique identifiers: the two tokens and the pool fee.
import { computePoolAddress, FeeAmount } from '@storyhunt/v3-sdk';
import { Token } from '@storyhunt/sdk-core';
const currentPoolAddress = computePoolAddress({
factoryAddress: POOL_FACTORY_CONTRACT_ADDRESS,
tokenA: token0,
tokenB: token1,
fee: poolFee,
});
Retrieve pool data by creating a reference to the poolβs smart contract:
import IPoolABI from '@storyhunt/v3-core/artifacts/contracts/interfaces/IPool.sol/IPool.json';
const poolContract = new ethers.Contract(
currentPoolAddress,
IPoolABI.abi,
provider
);
const [liquidity, slot0] = await Promise.all([
poolContract.liquidity(),
poolContract.slot0(),
]);
Create the pool instance:
import { Pool } from '@storyhunt/v3-sdk';
const configuredPool = new Pool(
token0,
token1,
poolFee,
slot0.sqrtPriceX96.toString(),
liquidity.toString(),
slot0.tick
);
Calculating a Position from Input Tokens
Using the pool instance, create a Position
class to define the price range for providing liquidity:
import { Position } from '@storyhunt/v3-sdk';
import { BigIntish } from '@storyhunt/sdk-core';
const position = Position.fromAmounts({
pool: configuredPool,
tickLower: nearestUsableTick(configuredPool.tickCurrent, configuredPool.tickSpacing) - configuredPool.tickSpacing * 2,
tickUpper: nearestUsableTick(configuredPool.tickCurrent, configuredPool.tickSpacing) + configuredPool.tickSpacing * 2,
amount0: amount0,
amount1: amount1,
useFullPrecision: true,
});
Configuring and Executing the Minting Transaction
Pass the Position
instance to the NonfungiblePositionManager
class to generate the calldata for minting a new position. Use the MintOptions
object to configure transaction parameters:
import { MintOptions, NonfungiblePositionManager } from '@storyhunt/v3-sdk';
import { Percent } from '@storyhunt/sdk-core';
const mintOptions: MintOptions = {
recipient: address,
deadline: Math.floor(Date.now() / 1000) + 60 * 20,
slippageTolerance: new Percent(50, 10_000),
};
const { calldata, value } = NonfungiblePositionManager.addCallParameters(
position,
mintOptions
);
Create and send the transaction:
const transaction = {
data: calldata,
to: NONFUNGIBLE_POSITION_MANAGER_CONTRACT_ADDRESS,
value: value,
from: address,
maxFeePerGas: MAX_FEE_PER_GAS,
maxPriorityFeePerGas: MAX_PRIORITY_FEE_PER_GAS,
};
const wallet = new ethers.Wallet(privateKey, provider);
const txRes = await wallet.sendTransaction(transaction);
The transaction mints a new position NFT, representing your liquidity in the specified pool.
Next Steps
After minting a position, you can manage it by adding or removing liquidity as needed. Explore advanced features to optimize your liquidity management in the Storyhunt V3 protocol.