Approval

In order for Kima to move tokens on behalf of the user an on chain approval needs to happen. An approval has 3 components:

  • Owner address: User

  • Spender address: Kima Pool

  • Total amount: origin token amount plus gas fees

Getting the Kima Pool Address

Chain
Type
Pool Address

EVM

ecdsa

0x9a721c664f9d69e4da24f91386086fbd81da23c1

Solana

eddsa

5tvyUUqPMWVGaVsRXHoQWqGw6h9uifM45BHCTQgzwSdr

Tron

ecdsa (base58)

t3JFtrr3JVedB1oH6v1AUNSqqFZk4E5U

You can also obtain the pool addresses from the TSS endpoint. Use the type in the chart above to determine which one to use.

GET https://api.sardis.kima.network/kima-finance/kima-blockchain/kima/tss_pubkey

Success Response:

  • tssPubkey (array object)

    • tssPubKey: string

    • ecdsa: string

    • eddsa: string

    • reserved: string

  • pagination (object)

    • nextKey: string | null

    • total: number

Note: for Tron, the hex esdsa address must be converted to a base 58 checksum address.

Getting the Service Fee

To calculate the total amount, the service (gas) fees are needed. Kima has an endpoint that estimates the service and gas fees for a given chain.

GET https://fee.kima.network/fee/{chainName}

Example: https://fee.kima.network/fee/AVX

{
  "result": "ok",
  "fee": "0.03-1729530600285-0.00124160"
}

Response

  • result: boolean

  • fee: string: dash delimited list <Amount USD>-<Timestamp>-<Amount Crypto>

  • Amount USD: the service fee amount in USD

  • Timestamp: Javascript timestamp in milliseconds

  • Amount Crypto: the fee amount in the native token of the given chain- i.e. AVAX

Chain Names

See the short names in the Supported assets section.

Calculating the Service Fee

To calculate the total service fee requires querying for the fees on both the source and target chains using the endpoint described above. There are a couple exceptions:

The fee is ZERO in the following cases as it is handled elsewhere:

  • Source or target chain is FIAT

  • Target chain is BTC

There is a constant value when the source chain is BTC:

  • Source chain is BTC: 0.0004 BTC

Since the source and target chains can be different, the USD amount fee amounts should be used and added together. The user will pay the fee using the source token. Remember, even stable coins are not exactly one USD, so the USD fee amount should be converted into the source token amount using the USD price of the source token.

Total Fees USD = source chain gas + target chain gas
Total Fees Source = Total Fees USD x Source Token per USD

Code Sample

Putting it all together, the following is a typescript code example that queries the endpoint and calculates the total service fee.

export enum ChainName {  
  ARBITRUM = 'ARB',  
  AVALANCHE = 'AVX',  
  BSC = 'BSC',  
  BTC = 'BTC'  
  ETHEREUM = 'ETH',  
  FIAT = 'FIAT',  
  OPTIMISM = 'OPT',  
  POLYGON = 'POL',    
  SOLANA = 'SOL',  
  TRON = 'TRX',  
}

const feeURL = 'https://fee.kima.network';

export async function calcServiceFee(  
  sourceChain: ChainName,  
  targetChain: ChainName  
): Promise<number> {  
    // exceptions  
    if (sourceChain === ChainName.FIAT || targetChain === ChainName.FIAT) {  
      return 0;  
    }

    if (sourceChain === ChainName.BTC) {  
      return 0.0004;  
    }

    if (targetChain === ChainName.BTC) {  
      return 0;  
    }

    const [sourceFee, targetFee] = await Promise.all([
      getServiceFee(sourceChain),  
      getServiceFee(targetChain)  
    ]);

    const fee = sourceFee + targetFee;

    // TODO: convert amount into source token amount  
    // using USD price of source token  
    // Note even stable coins are often not exactly 1:1

    return fee;  
}

async function getServiceFee(chain: ChainName): Promise=number= {  
  const result = await fetch(`${feeURL}/fee/${chain}`)  
    .then(res => res.json());

  // parse the dash separated fee  
  // <Amount USD>-<Timestamp>-<Amount Crypto>
  // we want the USD amount  
  const { fee } = result as { fee: string };  
  const [ amount ] = fee.split('-');  
   
  return +amount;  
}

Calling Approve

Once all the info has been collected it’s time to make the on chain call. The exact details of how this is done depends on the origin chain and library used.

Example code using typescript and Viem

import { getClientsForChain, getPoolAddressesForChain, getServiceFee } from "../utils";

export async function approve(chain: ChainName, userAddress: Address, amount: number) {  
  const { publicClient, walletClient } = getClientsForChain(chain);  
  const { contractAddress, decimals, poolAddress} = getPoolAddressesForChain(chain);  
   
  // calc total amount including fees  
  const fees = await getServiceFee(chain);  
  const totalAmount = amount + fees;  
  const intAmount = parseUnits(totalAmount.toString(), decimals);  
   
  // simulate approval call  
  const { request } = await publicClient.simulateContract({  
    account: userAddress,  
    address: contractAddress,  
    abi: erc20Abi,  
    functionName: 'approve',  
    args: [ poolAddress, intAmount ]
  });

  const hash = await walletClient.writeContract(request);

  const receipt = await publicClient.waitForTransactionReceipt({ hash });

  return receipt;  
}

This snippet uses the getServiceFee() function mentioned above. The getClientsForChain() and getPoolAdressesForChain() would be utility functions defined elsewhere.

Last updated