Open a Position

The openPosition function is used to open a new farming position. This function requires, as input, the FarmingPositionRequest struct:
function openPosition(FarmingPositionRequest memory request) public override payable activeSetupOnly(request.setupIndex) returns(uint256 positionId) {
At the moment of creation, a positionID that represents the position is generated:
positionId = uint256(keccak256(abi.encode(uniqueOwner);
Each generated id is encoded with the uniqueOwner (owner position) address. This means that each address can correspond to one and only one position within each setup; a single address cannot have multiple positions in a setup.
A user can also open a position for another address. In this case, the uniqueOwner is not the msg.sender, but rather the address passed in the FarmingPositionRequest:
address uniqueOwner = (request.positionOwner != address(0)) ? request.positionOwner : msg.sender;
Initial liquidity is transferred from the farmer to the contract and added and added to the setup via the _addLiquidity function, which calculates the amount (liquidityAmount) as well as the minted NFT’s id.
(uint256 tokenId, uint128 liquidityAmount) = _addLiquidity(request.setupIndex, request, 0);
‌In fact, when a user opens a position, the _addLiquidity function uses the Uniswap v3 MultiCall method to mint the NFT (and, in doing so, generate the NFT’s id) using the parameters established when the setup was created by the host.
(_addLiquidity can then call the increaseLiquidity method of INonfungiblePositionManager).
data[0] = abi.encodeWithSelector(nonfungiblePositionManager.increaseLiquidity.selector, abi.encode(INonfungiblePositionManager.IncreaseLiquidityParams({
tokenId: _setups[request.setupIndex].objectId,
amount0Desired: request.amount0,
amount1Desired: request.amount1,
amount0Min: 1,
amount1Min: 1,
deadline: block.timestamp + 10000
(tokenId, liquidityAmount, amount0, amount1) = abi.decode(IMulticall(address(nonfungiblePositionManager)).multicall{ value: ethValue }(data)[0], (uint256, uint128, uint256, uint256));
At this point, the FarmingPosition struct for the created position is populated as follow:
_positions[positionId] = FarmingPosition({ uniqueOwner: uniqueOwner, setupIndex : request.setupIndex, tokenId: tokenId, mainTokenAmount: mainTokenAmount, reward: reward, lockedRewardPerBlock: lockedRewardPerBlock, creationBlock: block.number
Creating a position increases the number of positions within a specific setup by one, given by:
mapping(uint256 => uint256) private _setupPositionsCount;
_setupPositionsCount[request.setupIndex] += 1