Create a New Pool

Create a new HBAR/token or token/token liquidity pool.

There are two methods to add a new liquidity pool:

See Pool creation fee to get the current pool creation fee.

Ensure that the liquidity pool does not exist on-chain prior to creation of the new pool. See Check for an existing pool.

Increase the client's max token auto-association by one to receive the incoming LP token.

To add liquidity to an existing pool, see Adding liquidity.

Both methods supports HTS tokens with custom fees.


Creating a New HBAR/Token Liquidity Pool

Create a new HBAR/token liquidity pool and provide it with initial liquidity.

Function name: addLiquidityETHNewPool

Recommended gas: 3,200,000 gwei (~ $0.27 USD)

Solidity Interface & Function Body
//IUniswapV2Router01.sol

function addLiquidityETHNewPool(
  address token,
  uint amountTokenDesired,
  uint amountTokenMin,
  uint amountETHMin,
  address to,
  uint deadline
) external payable returns (uint amountToken, uint amountETH, uint liquidity);
//UniswapV2Router02.sol

function addLiquidityETHNewPool(
  address token,
  uint amountTokenDesired,
  uint amountTokenMin,
  uint amountETHMin,
  address to,
  uint deadline
) external virtual payable override ensure(deadline) returns (uint amountToken, uint amountETH, uint liquidity) {
  require (IUniswapV2Factory(factory).getPair(token, whbar) == address(0), "UniswapV2Router: POOL ALREADY EXISTS");
  uint256 feeInTinybars = tinycentsToTinybars(IUniswapV2Factory(factory).pairCreateFee());
  require(msg.value > feeInTinybars, 'UniswapV2Router: MSG.VALUE');
  IUniswapV2Factory(factory).createPair{value: feeInTinybars}(token, whbar);

  (amountToken, amountETH) = _addLiquidity(token, whbar, amountTokenDesired, msg.value - feeInTinybars, amountTokenMin, amountETHMin);
  address pair = UniswapV2Library.pairFor(factory, token, whbar);
  
  safeTransferToken(
    token, msg.sender, pair, amountToken
  );
  IWHBAR(WHBAR).deposit{value: amountETH}(msg.sender, pair);
  liquidity = IUniswapV2Pair(pair).mint(to);
  if (msg.value - feeInTinybars > amountETH) TransferHelper.safeTransferETH(msg.sender, msg.value - feeInTinybars - amountETH);
}

A spender allowance for the router is required for the HTS token.

The addLiquidityETHNewPool function operates in HBAR but derives its name from Uniswap on Ethereum. This name was kept to simplify integration for developers versed in Uniswap tools.

Code Overview

Resources:

import { 
  ContractFunctionParameters, 
  ContractExecuteTransaction,
  AccountAllowanceApproveTransaction,
  AccountUpdateTransaction, //for token auto-association
  .. 
} from '@hashgraph/sdk';

//Client pre-checks:
// - Max auto-association increased by one
// - Router contract has spender allowance for the input token

const params = new ContractFunctionParameters();
params.addAddress(tokenAddress); //address token
params.addUint256(amountTokenDesired); //uint amountTokenDesired
params.addUint256(amountTokenMin); //uint amountTokenMin
params.addUint256(amountHBARMin); //uint amountETHMin
params.addAddress(toAddress); //address to
params.addUint256(deadline); //uint deadline
    
const response = await new ContractExecuteTransaction()
 .setPayableAmount(inputHbarAndPoolCreationFeeHbar) //input hbar + pool creation fee
 .setContractId(routerContractId)
 .setGas(gasLim)
 .setFunction('addLiquidityETHNewPool', params)
 .execute(client);
 
const record = await response.getRecord(client);
const result = record.contractFunctionResult!;
const values = result.getResult(['uint','uint','uint']);
const amountToken = values[0]; //uint amountToken
const amountHBAR = values[1]; //uint amountETH
const liqudity = values[2]; //uint liquidity


Creating a New Token/Token Liquidity Pool

Create a new token/token liquidity pool and provide it with initial liquidity.

Function name: addLiquidityNewPool

Recommended gas: 3,200,000 gwei (~ $0.27 USD)

Solidity Interface & Function Body
//IUniswapV2Router01.sol

function addLiquidityNewPool(
  address tokenA,
  address tokenB,
  uint amountADesired,
  uint amountBDesired,
  uint amountAMin,
  uint amountBMin,
  address to,
  uint deadline
) external payable returns (uint amountA, uint amountB, uint liquidity);
//UniswapV2Router02.sol

function addLiquidityNewPool(
  address tokenA,
  address tokenB,
  uint amountADesired,
  uint amountBDesired,
  uint amountAMin,
  uint amountBMin,
  address to,
  uint deadline
) external virtual payable override ensure(deadline) returns (uint amountA, uint amountB, uint liquidity) {
  
  require (IUniswapV2Factory(factory).getPair(tokenA, tokenB) == address(0), "UniswapV2Router: POOL ALREADY EXISTS");
  address pair = IUniswapV2Factory(factory).createPair{value: msg.value}(tokenA, tokenB);
  
  (amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin);

  safeTransferToken(
    tokenA, msg.sender, pair, amountA
  );
  safeTransferToken(
    tokenB, msg.sender, pair, amountB
  );
  liquidity = IUniswapV2Pair(pair).mint(to);
}

A spender allowance for the router is required for both HTS tokens.

Code Overview

Resources:

import { 
  ContractFunctionParameters, 
  ContractExecuteTransaction,
  AccountAllowanceApproveTransaction,
  AccountUpdateTransaction, //for token auto-association
  .. 
} from '@hashgraph/sdk';

//Client pre-checks:
// - Max auto-association increased by one
// - Router contract has spender allowance for the input tokens

const params = new ContractFunctionParameters();
params.addAddress(tokenAEvmAddress); //address tokenA
params.addAddress(tokenBEvmAddress); //address tokenB
params.addUint256(amountADesired); //uint amountADesired
params.addUint256(amountBDesired); //uint amountBDesired
params.addUint256(amountAMin); //uint amountAMin
params.addUint256(amountBMin); //uint amountBMin
params.addAddress(toEvmAddress); //address to
params.addUint256(deadline); //uint deadline
    
const response = await new ContractExecuteTransaction()
 .setPayableAmount(poolCreationFeeHbar)
 .setContractId(routerContractId)
 .setGas(gasLim)
 .setFunction('addLiquidityNewPool', params)
 .execute(client);
 
const record = await response.getRecord(client);
const result = record.contractFunctionResult!;
const values = result.getResult(['uint','uint','uint']);
const amountA = values[0]; //uint amountA - in its smallest unit
const amountB = values[1]; //uint amountB - in its smallest unit
const liquidity = values[2]; //uint liquidity

Last updated