Algebra Integral Overview
  • Intro
  • Audits
  • Integration of Algebra Integral protocol
    • Specification and API of contracts
      • Algebra Pool
      • Algebra Factory
      • Swap Router
      • Nonfungible Position Manager
      • Quoter
      • QuoterV2
      • TickLens
    • Interaction with pools
      • Getting data from pools
    • Subgraphs and analytics
      • Examples of queries
    • Technical guides
      • Intro
      • Swaps
        • Single swaps
        • Multihop swaps
      • Providing liquidity
        • Setting up your contract
        • Mint a new position
        • Collect fees
        • Decrease liquidity
        • Increase liquidity
        • Final contract
      • Flashloans
        • Setting up your contract
        • Calling flash
        • Flash callback
        • Final contract
    • Migration from UniswapV3
  • Core logic
    • Pool overview
    • Swap calculation
    • Liquidity and positions
    • Ticks
      • Ticks search tree
    • Reserves
    • Flash
    • Plugins
    • AlgebraFactory and roles
  • Plugins
    • Intro
  • Changes after V1
Powered by GitBook
On this page
  • Input Parameters
  • Calling Mint
  • Updating The Deposit Mapping And Refunding The Calling Address
  • The Full Example
  1. Integration of Algebra Integral protocol
  2. Technical guides
  3. Providing liquidity

Mint a new position

Input Parameters

To mint a new position, we use the nonFungiblePositionManager and call mint.

For this exact example, we’re hard-coding the token amounts to be minted. In production, this would be a user-configurable function argument.

    /// @notice Calls the mint function defined in periphery, mints the same amount of each token. For this example we are providing 1000 DAI and 1000 USDC in liquidity
    /// @return tokenId The id of the newly minted ERC721
    /// @return liquidity The amount of liquidity for the position
    /// @return amount0 The amount of token0
    /// @return amount1 The amount of token1
    function mintNewPosition()
        external
        returns (
            uint256 tokenId,
            uint128 liquidity,
            uint256 amount0,
            uint256 amount1
        )
    {
        // For this example, we will provide equal amounts of liquidity in both assets.
        // Providing liquidity in both assets means liquidity will be earning fees and is considered in-range.
        uint256 amount0ToMint = 1000;
        uint256 amount1ToMint = 1000;

Calling Mint

Here we approve the nonfungiblePositionManager to use the contracts' tokens, then populate the MintParams struct and assign it to a local variable params that will be passed to the nonfungiblePositionManager when we call mint.

  • By using TickMath.MIN_TICK and TickMath.MAX_TICK, we are providing liquidity across the whole pool’s range. In production, you may want to specify a more concentrated position.

  • We set amount0Min and amount1Min to zero for the example - but this would be a vulnerability in production. A function calling mint with no slippage protection would be vulnerable to a front running attack designed to execute the mint call at an inaccurate price.

  • For more reliable practice, the developer needs to implement a slippage assessment process.

  • Note that this function will not initialize a pool where one does not yet exist.

        // Approve the position manager
        TransferHelper.safeApprove(DAI, address(nonfungiblePositionManager), amount0ToMint);
        TransferHelper.safeApprove(USDC, address(nonfungiblePositionManager), amount1ToMint);

        INonfungiblePositionManager.MintParams memory params =
            INonfungiblePositionManager.MintParams({
                token0: DAI,
                token1: USDC,
                tickLower: TickMath.MIN_TICK,
                tickUpper: TickMath.MAX_TICK,
                amount0Desired: amount0ToMint,
                amount1Desired: amount1ToMint,
                amount0Min: 0,
                amount1Min: 0,
                recipient: address(this),
                deadline: block.timestamp
            });

        // Note that the pool defined by DAI/USDC must already be created and initialized in order to mint
        (tokenId, liquidity, amount0, amount1) = nonfungiblePositionManager.mint(params);

Updating The Deposit Mapping And Refunding The Calling Address

        // Create a deposit
        _createDeposit(msg.sender, tokenId);

        // Remove allowance and refund in both assets.
        if (amount0 < amount0ToMint) {
            TransferHelper.safeApprove(DAI, address(nonfungiblePositionManager), 0);
            uint256 refund0 = amount0ToMint - amount0;
            TransferHelper.safeTransfer(DAI, msg.sender, refund0);
        }

        if (amount1 < amount1ToMint) {
            TransferHelper.safeApprove(USDC, address(nonfungiblePositionManager), 0);
            uint256 refund1 = amount1ToMint - amount1;
            TransferHelper.safeTransfer(USDC, msg.sender, refund1);
        }
    }

The Full Example

    /// @notice Calls the mint function defined in periphery, mints the same amount of each token. For this example we are providing 1000 DAI and 1000 USDC in liquidity
    /// @return tokenId The id of the newly minted ERC721
    /// @return liquidity The amount of liquidity for the position
    /// @return amount0 The amount of token0
    /// @return amount1 The amount of token1
    function mintNewPosition()
        external
        returns (
            uint256 tokenId,
            uint128 liquidity,
            uint256 amount0,
            uint256 amount1
        )
    {
        // For this example, we will provide equal amounts of liquidity in both assets.
        // Providing liquidity in both assets means liquidity will be earning fees and is considered in-range.
        uint256 amount0ToMint = 1000;
        uint256 amount1ToMint = 1000;

        // Approve the position manager
        TransferHelper.safeApprove(DAI, address(nonfungiblePositionManager), amount0ToMint);
        TransferHelper.safeApprove(USDC, address(nonfungiblePositionManager), amount1ToMint);

        INonfungiblePositionManager.MintParams memory params =
            INonfungiblePositionManager.MintParams({
                token0: DAI,
                token1: USDC,
                tickLower: TickMath.MIN_TICK,
                tickUpper: TickMath.MAX_TICK,
                amount0Desired: amount0ToMint,
                amount1Desired: amount1ToMint,
                amount0Min: 0,
                amount1Min: 0,
                recipient: address(this),
                deadline: block.timestamp
            });

        // Note that the pool defined by DAI/USDC must already be created and initialized in order to mint
        (tokenId, liquidity, amount0, amount1) = nonfungiblePositionManager.mint(params);

        // Create a deposit
        _createDeposit(msg.sender, tokenId);

        // Remove allowance and refund in both assets.
        if (amount0 < amount0ToMint) {
            TransferHelper.safeApprove(DAI, address(nonfungiblePositionManager), 0);
            uint256 refund0 = amount0ToMint - amount0;
            TransferHelper.safeTransfer(DAI, msg.sender, refund0);
        }

        if (amount1 < amount1ToMint) {
            TransferHelper.safeApprove(USDC, address(nonfungiblePositionManager), 0);
            uint256 refund1 = amount1ToMint - amount1;
            TransferHelper.safeTransfer(USDC, msg.sender, refund1);
        }
    }
PreviousSetting up your contractNextCollect fees

Last updated 1 year ago

After the previous point, we can call the internal function we previously wrote in . After that, we can take any liquidity leftover from minting and refund it to msg.sender.

Setting Up Your Contract