Swap Tokens for Tokens

Swap HTS fungible tokens for HTS fungible tokens.

Below are three methods available to swap tokens for tokens:

Consider the token's decimal places when determining input and output values.

Input and output amounts passed to the solidity function should all be in the token's smallest unit. For the SAUCE token, which has 6 decimal places, an input of 123.45 SAUCE should be entered as 123450000 (123.45 multiplied by 10^6).

Granting an spender allowance to the router contract is required when the input token is not native HBAR for security reasons enforced at the native code layer . Ensure that the allowance amount is in token's smallest unit.

Ensure that the "to" account has the output token id associated prior to executing the swap. Failure to do so will result in a TOKEN_NOT_ASSOCIATED_TO_ACCOUNT error.


Swap Exact Tokens for Tokens

Swap an exact amount of tokens for a minimum token amount.

Solidity function name: swapExactTokensForTokens

Parameter Name
Description

uint amountIn

The exact input token amount in its smallest unit

uint amountOutMin

The minimum token amount to receive in its smallest unit

address[] calldata path

An ordered list of token EVM addresses

address to

EVM address for the token recipient

uint deadline

Deadline in unix seconds

Solidity Interface & Function Body
//IUniswapV2Router01.sol

function swapTokensForExactTokens(
  uint amountOut,
  uint amountInMax,
  address[] calldata path,
  address to,
  uint deadline
) external returns (uint[] memory amounts);
//UniswapV2Router02.sol

function swapTokensForExactTokens(
  uint amountOut,
  uint amountInMax,
  address[] calldata path,
  address to,
  uint deadline
) external virtual override ensure(deadline) returns (uint[] memory amounts) {
  amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
  require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');

  safeTransferToken(
    path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
  );
  _swap(amounts, path, to);
}

Code Overview

Resources:

import { 
  ContractFunctionParameters, 
  ContractExecuteTransaction,
  AccountAllowanceApproveTransaction,  
  TokenAssociateTransaction,
  .. 
} from '@hashgraph/sdk';

//Client pre-checks:
// - Output token is associated
// - Router contract has spender allowance for the input token

const params = new ContractFunctionParameters();
params.addUint256(amountIn); //uint amountIn
params.addUint256(amountOutMin); //uint amountOutMin
params.addAddressArray(tokenPath); //address[] calldata path
params.addAddress(toAddress); //address to
params.addUint256(deadline); //uint deadline
    
const record = await new ContractExecuteTransaction()
 .setContractId(routerContractId)
 .setGas(gasLim)
 .setFunction('swapExactTokensForTokens', params)
 .execute(client);
 
const record = await response.getRecord(client);
const result = record.contractFunctionResult!;
const values = result.getResult(['uint[]']);
const amounts = values[0]; //uint[] amounts
const finalOutputAmount = amounts[amounts.length - 1];


Swap Tokens for Exact Tokens

Swap a maximum amount of tokens to receive an exact tokens amount.

Solidity function name: swapTokensForExactTokens

Parameter name
Description

uint amountOut

The exact output amount to receive in its smallest unit

uint amountInMax

The maximum allowed input amount in its smallest unit

address[] calldata path

An ordered list of token EVM addresses

address to

EVM address for the token recipient

uint deadline

Deadline in unix seconds

Solidity Interface & Function Body
//IUniswapV2Router01.sol

function swapTokensForExactTokens(
  uint amountOut,
  uint amountInMax,
  address[] calldata path,
  address to,
  uint deadline
) external returns (uint[] memory amounts);
//UniswapV2Router02.sol

function swapTokensForExactTokens(
  uint amountOut,
  uint amountInMax,
  address[] calldata path,
  address to,
  uint deadline
) external virtual override ensure(deadline) returns (uint[] memory amounts) {
  amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
  require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');

  safeTransferToken(
    path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
  );
  _swap(amounts, path, to);
}

Code Overview

Resources:

import { 
  ContractFunctionParameters, 
  ContractExecuteTransaction,
  AccountAllowanceApproveTransaction,  
  TokenAssociateTransaction,
  .. 
} from '@hashgraph/sdk';

//Client pre-checks:
// - Output token is associated
// - Router contract has spender allowance for the input token

const params = new ContractFunctionParameters();
params.addUint256(amountOut); //uint amountOut
params.addUint256(amountInMax); //uint amountInMax
params.addAddressArray(tokenPath); //address[] calldata path
params.addAddress(toAddress); //address to
params.addUint256(deadline); //uint deadline
    
const response = await new ContractExecuteTransaction()
 .setContractId(routerContractId)
 .setGas(gasLim)
 .setFunction('swapTokensForExactTokens', params)
 .execute(client);
 
const record = await response.getRecord(client);
const result = record.contractFunctionResult!;
const values = result.getResult(['uint[]']);
const amounts = values[0]; //uint[] amounts
const finalInputAmount = amounts[0];

Swap Exact Tokens for Tokens Supporting Custom Fees

Swap an exact amount of tokens for a minimum HBAR amount, supporting HTS tokens with custom fees on token transfer.

Solidity function name: swapExactTokensForTokensSupportingFeeOnTransferTokens

Parameter Name
Description

uint amountIn

The input token amount in its smallest unit

uint amountOutMin

The minimum token amount to receive in its smallest unit

address[] calldata path

An ordered list of token EVM addresses

address to

EVM address for the token recipient

uint deadline

Deadline in unix seconds

Solidity Interface & Function Body
//IUniswapV2Router02.sol

function swapExactTokensForTokensSupportingFeeOnTransferTokens(
  uint amountIn,
  uint amountOutMin,
  address[] calldata path,
  address to,
  uint deadline
) external;
//UniswapV2Router02.sol

function swapExactTokensForTokensSupportingFeeOnTransferTokens(
  uint amountIn,
  uint amountOutMin,
  address[] calldata path,
  address to,
  uint deadline
) external virtual override ensure(deadline) {
  
  safeTransferToken(
    path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn
  );
  uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
  _swapSupportingFeeOnTransferTokens(path, to);
  require(
    IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin,
    'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'
  );
}

Code Overview

Resources:

import { 
  ContractFunctionParameters, 
  ContractExecuteTransaction,
  AccountAllowanceApproveTransaction,  
  TokenAssociateTransaction,
  .. 
} from '@hashgraph/sdk';

//Client pre-checks:
// - Output token is associated
// - Router contract has spender allowance for the input token

const params = new ContractFunctionParameters();
params.addUint256(amountIn); //uint amountIn
params.addUint256(amountOutMin); //uint amountOutMin
params.addAddressArray(tokenPath); //address[] calldata path
params.addAddress(toAddress); //address to
params.addUint256(deadline); //uint deadline
    
await new ContractExecuteTransaction()
 .setContractId(routerContractId)
 .setGas(gasLim)
 .setFunction('swapExactTokensForTokensSupportingFeeOnTransferTokens', params)
 .execute(client);

Last updated