Approval

Before Kima can move user funds, the origin asset must be authorized through the mechanism that applies to that flow:

  • Regular ERC-20 tokens use an on-chain approve() transaction

  • Permit2 tokens use a signature-based approval flow

  • BTC-origin flows use an HTLC lock instead of ERC-20 approval

For regular ERC-20 approvals, there are 3 core components:

  • Owner address: User

  • Spender address: Kima Pool

  • Total amount: origin token amount plus gas fees

Getting the Kima Pool Address

Using the Kima Backend

GET /chains/pool returns a list of pool addresses and balances for all supported chains.

[
  {
    "chainName": "SOL",
    "poolAddress": "5tvyUUqPMWVGaVsRXHoQWqGw6h9uifM45BHCTQgzwSdr",
    "balance": [
      {
        "amount": "99684.841000000000000000",
        "tokenSymbol": "USDK",
        "decimal": "6"
      }
    ],
    "nativeGasAmount": "70.119964040000000000"
  },
  {
    "chainName": "TRX",
    "poolAddress": "TQ3qmAgUgMwrY9prMiHLZmF43G4Jk8bxNF",
    "balance": [],
    "nativeGasAmount": ""
  }
]

Using the Kima API

Chain
Type
Pool Address

EVM

ecdsa

0x9a721c664f9d69e4da24f91386086fbd81da23c1

Solana

eddsa

5tvyUUqPMWVGaVsRXHoQWqGw6h9uifM45BHCTQgzwSdr

Tron

ecdsa (base58)

TQ3qmAgUgMwrY9prMiHLZmF43G4Jk8bxNF

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

Use the environment-appropriate API base URL:

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

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

Bitcoin is also supported. For BTC, prefer GET /chains/pool from the backend; the backend derives the BTC pool address from the TSS data (reserved or ecdsaPubkey) for the active environment.

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 ecdsa address must be converted to a base 58 checksum address.

Getting the Service Fee

The fees and token authorization amounts are calculated by an endpoint exposed by Kima chain. This endpoint also returns a feeId which must be included when submitting the transaction.

Using the Kima Backend

GET /submit/fees

Query Params (all required):

  • amount (number): the amount of tokens to transfer

  • originAddress (string): the source user address

  • originChain (string): the chain the user tokens will come from

  • originSymbol (string): the token symbol the user will pay with (or bridge from)

  • targetAddress (string): the receiving address

  • targetChain (string): the destination chain

  • targetSymbol (string): the token symbol being delivered

Example:

Port note: these direct backend examples use the backend's default local port 3001. If your frontend or local proxy exposes the backend on another port such as 4000, use that URL instead.

Example note: these sample fee requests and responses use USDK, which is a testnet token. If you are integrating against mainnet, replace it with a supported mainnet token such as USDC.

Success Response:

Amounts are returned as both numbers representing the amount in whole tokens and as a string representing the integer amount in the smallest unit of the token (e.g. USDC is 6 decimals).

  • feeId (string): a unique identifier for the fee; include this in the submit request (/submit/transfer or /submit/swap)

  • feeOrigin* the gas fee for the origin chain

  • feeKimaProcessing* The processing fee (currently 0.05%)

  • feeTarget* the gas fee for the target chain

  • feeTotal* the total fee

  • transactionValues: amounts used for token authorization and for submitting the transaction

    • feeFromOrigin: amounts used when the user selects to pay fees from the origin amount

      • allowanceAmount: the token amount to authorize. For regular ERC-20 tokens this is the value to pass to approve(). For Permit2 tokens, use it when building the Permit2 authorization/signature flow.

      • submitAmount: the amount that needs to be passed to submit endpoints

    • feeFromTarget: amounts used when the user selects to pay fees from the target amount

The response field is still named allowanceAmount, but treat it as the origin token authorization amount. There are 2 variants returned depending on whether the user chooses to pay fees from the origin or target amount.

  • When paying fees from the origin, use transactionValues.feeFromOrigin values.

  • When paying fees from the target, use transactionValues.feeFromTarget.

Example:

Transferring 10 USDK from ARB to SOL with 0.07371 USD in total fees.

When paying fees from the origin

  • The total fees are added to the amount

  • User signs the message I approve the transfer of 10.07371 USDK from ARB to 5FHwkrdxkjF7xoL2ncGh4AEYs1KyJzz5MeiaHGz8h8GA on SOL. (feeFromOrigin.message)

  • The authorization amount is 10.07371 USDK (feeFromOrigin.allowanceAmount)

  • For regular ERC-20 tokens, use that value in approve(). For Permit2 tokens, use it in the Permit2 authorization flow.

  • The amount sent to submit endpoints is amount RECEIVED on the target chain

  • The amount sent to submit endpoints is 10 USDK (feeFromOrigin.submitAmount)

    • Also included is the feeId and signed message

  • The user receives 10 USDK on Solana

When paying fees from the target chain

  • The user does not pay fees on Arbitrum

  • User signs the message I approve the transfer of 10 USDK from ARB to 5FHwkrdxkjF7xoL2ncGh4AEYs1KyJzz5MeiaHGz8h8GA on SOL. (feeFromTarget.message)

  • The authorization amount is 10 USDK (feeFromTarget.allowanceAmount)

  • For regular ERC-20 tokens, use that value in approve(). For Permit2 tokens, use it in the Permit2 authorization flow.

  • The amount sent to submit endpoints is 9.926290 USDK (feeFromTarget.submitAmount)

  • The fees are deducted from the amount received on Solana so the user receives 9.926290 USDK on Solana

Save the corresponding submitAmount, message and feeId for later as they are needed to submit the transaction.

Chain Names

See the short names in the Supported Assets section.

Using the Kima API

There is also an endpoint that can be called directly.

POST {{baseUrl}}/v3/fees/calculate

It has the same input/output purpose as the Backend /submit/fees endpoint except:

  • The params are in the body as JSON

  • There is an extra param creator which is the Kima address of the developer wallet sending the transaction- kima1...

For most integrations, GET /submit/fees remains the recommended wrapper because it keeps your app aligned with the backend contract.

Permit2 Tokens

Read the selected origin token metadata from GET /chains.

  • isPermit2=false: use the standard approve flow shown below.

  • isPermit2=true: signature is still required, and submit with options.permit2 payload (r, s, v, deadline) in addition.

  • Permit2 tokens are not supported in mode=light.

BTC-origin flow (approval equivalent)

BTC-origin transactions do not use ERC20 approve. Instead, funds are first locked in a BTC HTLC output and then submitted to Kima with HTLC metadata.

You should still call GET /submit/fees first and keep feeId for the final submit step.

Step 1: Create HTLC lock intent

POST /btc/htlc/lock-intent

Request body:

  • senderAddress (string): BTC sender address

  • senderPubkey (string): BTC sender public key (hex)

  • recipientAddress (string): recipient address used to construct the lock script

  • amountSats (string): lock amount in satoshis

  • poolAddress (string, optional): explicit BTC recipient in script

  • lockBlocks (number, optional): timeout as block delta

  • timeout (number, optional): explicit timeout value

Response includes:

  • lockId

  • htlcAddress

  • timeoutHeight

  • amountSats

  • senderPubkey

Step 2: Broadcast BTC lock transaction

Use the user's BTC wallet/provider to send amountSats to the returned htlcAddress. Save the broadcast transaction hash (txid).

Step 3: Record the broadcast transaction

POST /btc/htlc/record

Request body:

  • lockId

  • txid

Response returns submit-ready HTLC fields:

  • htlcCreationHash

  • htlcCreationVout

  • htlcExpirationTimestamp

  • htlcVersion (currently p2wsh-sha256-cltv-v1)

  • senderPubKey

Use these together with:

  • htlcAddress and htlcLockId from lock-intent

  • htlcAmountSats from the selected lock amount

These values are then sent to POST /submit/transfer or POST /submit/swap.

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.

The getClientsForChain() and getPoolAddressesForChain() would be utility functions defined elsewhere.

Last updated