# The Kima Transaction Back End

This is a web server that works as middleware between the Kima Transaction Widget and Kima Chain. Once it receives a transaction request from the widget, it will submit a transaction to Kima Chain signed by a local wallet.

The server is an Express application and requires minimal setup. Here are the instructions:

### Create a wallet for development purposes <a href="#create-a-wallet-for-development-purposes" id="create-a-wallet-for-development-purposes"></a>

We recommend Keplr, which is a widely used wallet for blockchains within the Cosmos ecosystem.

Install it from [here](https://www.keplr.app/download) and make sure you back it up by saving the seed phrase.

You will need to record the **mnemonic seed phrase** rather than the private key, as the seed phrase is used as an environment variable.

> ⚠️ In order to connect to the Kima chain (both Mainnet and Sardis Testnet), you will need to get your Kima address whitelisted. Please contact us at <dev@kima.finance> with your public address- it will start with `kima1`. This is a temporary measure to combat spammers.

You can find your Kima address in the Keplr wallet by

* Clicking the "Copy Address" button
* Find "Kima" in the list of chains
* Click the "Copy Address" button

If you have not yet added the Kima Network to Keplr, you can enter "Kima" in the "Search for a chain" field when copying the address.

![Get Kima Address from Keplr wallet](https://3134460121-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FJ6zSf6jJsAYmovV6Wkcr%2Fuploads%2Fgit-blob-4adf2b69c87c73ec7dc0df21bd9bb23829128602%2Fget_kima_address.png?alt=media)

### Get some KIMA tokens to use for transaction fees <a href="#get-some-kima-tokens-to-use-for-transaction-fees" id="get-some-kima-tokens-to-use-for-transaction-fees"></a>

If you are developing on the KIMA testnet, you can acquire test KIMA tokens from our [faucet site](https://faucet.kima.network). For mainnet, there is a list of exchanges where you can buy KIMA tokens [here](https://www.kima.network/kima).

Follow the [instructions here](https://docs.kima.network/kima-network/try-kima-with-the-demo-app/kima-faucets) if you have not used a faucet before.

### Clone the repo at: <a href="#clone-the-repo-at" id="clone-the-repo-at"></a>

<https://github.com/kima-finance/kima-transaction-backend>

### Set your environment variables <a href="#set-your-environment-variables" id="set-your-environment-variables"></a>

For local development, create a `.env` file in the project root and copy the relevant values from `.env.sample`.

This repository does not currently include `docker-compose.yml`, `docker-compose-prod.yml`, or separate `/env/*.env` files. If you containerize the backend in your own environment, pass the same variables from `.env.sample` through your deployment platform or container runtime.

The `.env` file will be ignored by git, but `.env.sample` is not, so do NOT accidentally fill real secrets into the sample file.

A few notes about these environment variables:

`KIMA_BACKEND_MNEMONIC` is the seed phrase from the wallet you installed. Never share this with anyone. Never commit this to a code repository. Use a secret manager service like [Google Secret Manager](https://cloud.google.com/security/products/secret-manager) or [AWS Secrets Manager](https://aws.amazon.com/secrets-manager/) to store your seed phrase instead of putting it in the `.env` file.

`KIMA_ENVIRONMENT` is separate from the `NODE_ENV` variable and determines whether information endpoints like `/chains` will return testnet or mainnet values.

`DOMAIN` is a comma separated list of urls that the server will accept requests from. All other domains will be blocked (except in the dev environment). Put the url of your frontend here.

`COMPLIANCE_URL` (OPTIONAL) If your app needs to block non-compliant addresses contact us for more information and the url to use here.

`/chains/env` returns the environment metadata expected by the widget. A typical response looks like this:

```json
{
  "env": "testnet",
  "kimaExplorer": "https://explorer.sardis.kima.network",
  "transferLimitMaxUSDT": "100.000000000000000000",
  "paymentPartnerId": "KimaTest"
}
```

Field meanings:

* `env`: active Kima environment used by the widget to configure network behavior
* `kimaExplorer`: explorer base URL used for status and transaction links
* `transferLimitMaxUSDT`: optional transfer cap used by light mode and validation logic
* `paymentPartnerId`: FIAT widget partner identifier used by widget-managed payment flows

#### Mainnet

Here are the mainnet specific environment variables. See the `.env.sample` for the most up to date list of ENV variables and default values. The other vars you will need to fill in with your specific values.

```shell
KIMA_BACKEND_FEE_URL=https://fcs.kima.network
KIMA_BACKEND_NODE_PROVIDER=https://rpc.kima.network
KIMA_BACKEND_NODE_PROVIDER_GRAPHQL=https://graphql.kima.network/v1/graphql
KIMA_BACKEND_NODE_PROVIDER_QUERY=https://api.kima.network
KIMA_ENVIRONMENT=mainnet
KIMA_EXPLORER=https://explorer.kima.network
PAYMENT_PARTNER_ID=Kima
```

#### Testnet

```shell
KIMA_BACKEND_FEE_URL=https://fcs.sardis.kima.network
KIMA_BACKEND_NODE_PROVIDER=https://rpc.sardis.kima.network
KIMA_BACKEND_NODE_PROVIDER_GRAPHQL=https://graphql.sardis.kima.network/v1/graphql
KIMA_BACKEND_NODE_PROVIDER_QUERY=https://api.sardis.kima.network
KIMA_ENVIRONMENT=testnet
KIMA_EXPLORER=https://explorer.sardis.kima.network
PAYMENT_PARTNER_ID=KimaTest
```

### Install and start <a href="#install-and-start" id="install-and-start"></a>

You can run:

`npm install`

then

`npm run dev`

If you deploy the backend in a container or cloud runtime, provide the same environment variables shown above through that platform's configuration.

### Test the installation <a href="#test-the-installation" id="test-the-installation"></a>

In your terminal, run the following command:

```bash
curl -i http://localhost:3001/health
```

The server should respond with a `200` and a JSON body similar to:

```json
{
  "ok": true,
  "env": "development"
}
```

## Available routes <a href="#available-routes" id="available-routes"></a>

See OpenAPI documentation at `/docs` for more details (only available when `NODE_ENV` is `development`). The following is an overview of how the routes are used together.

* Get various info for the frontend from `/chains/*` like supported chains, tokens, pool addresses, etc.
  * Token entries in `/chains` include `isPermit2` metadata. Use this to decide whether submit `options` must include a Permit2 payload.
* `GET /submit/fees`: get the service fees and token authorization amounts
  * The response includes `feeTotalFiat` and `feeTotalBigInt` for the total fee value.
  * Returns a ready-to-use `transactionValues.*.allowanceAmount` object with `value` and `decimals`, representing the origin token authorization amount. For regular ERC-20 tokens, pass the `value` using the accompanying `decimals` context to `approve()`. For Permit2 tokens, use the same amount data when building the Permit2 authorization flow. Bigints are used to avoid floating point errors.
  * The required authorization step must be completed before submitting the transaction or the transfer will fail.
  * Use the `submitAmount` when calling `/submit/transfer` or `/submit/swap`; it is already properly adjusted based on whether fees are deducted from origin or target.
  * Use the `decimals` property to convert to a number if needed elsewhere.
* `POST /submit/transfer`: initiates a transfer transaction and returns data containing the Kima transaction id
* `POST /submit/swap`: initiates a swap transaction and returns data containing the Kima transaction id
* `GET /tx/{txId}/status`: use the transaction id returned from submit to get the transaction status
* BTC route group (`/btc/*`) for BTC-origin flows:
  * `GET /btc/balance?address={address}`: fetch BTC balance (sats) for an address
  * `POST /btc/htlc/lock-intent`: create HTLC lock intent and return lock metadata
  * `POST /btc/htlc/record`: record a broadcast BTC lock transaction and return submit-ready HTLC fields
  * `GET /btc/height`: get current BTC chain height from configured mempool backend
  * `GET /btc/tip`: get current BTC tip height and timestamp
  * `GET /btc/outspend?txid={txid}&vout={index}`: fetch spend status for a specific transaction output
  * `GET /btc/transaction?hash={txid}`: fetch BTC transaction details
  * `GET /btc/utxo/{address}`: fetch UTXO set for an address

### Permit2 Tokens

For origin tokens where `/chains` reports `isPermit2: true`:

* submit payload `options.signature` is still required
* submit payload `options` must include `permit2`
* `permit2` requires `r`, `s`, `v`, `deadline`
* `mode=light` is not supported for Permit2 tokens

### What is an HTLC lock?

In BTC-origin flows, funds are first sent to an HTLC address. This creates an on-chain lock with a timeout.

* Before timeout: funds are handled according to the HTLC conditions.
* After timeout: the lock can be reclaimed according to HTLC rules.

In Kima, that BTC lock transaction is recorded via `/btc/htlc/record`, and the returned HTLC metadata is attached to `/submit/transfer` or `/submit/swap`.

### Expected timing model for BTC-origin flow

Timing is confirmation-based and variable.

* BTC confirmation threshold is chain-parameter driven (default BTC confirmation blocks: `6`).
* Observer validation waits until the required number of confirmations is reached.
* Observer hash collection and processing run on a periodic cadence (about every `5` seconds).

Because mempool, block production, and validator consensus timings vary, this flow should be treated as variable-time (no fixed minute SLA).

## Optional Features

### Custom Transaction Validation

In `/src/custom-transaction-validation.ts` you can add your own custom validation logic. Kima does not know the requirements of your app, so it is up to you to make sure the transaction makes sense. This is a convenience function, feel free to modify the middleware if you need lower level access.

The `customTransValidation` function

* Will be called in middleware after basic param validation and before the `/submit/transfer` or `/submit/swap` route handler is called
* Should return a `string` with the error message or the empty string if the transaction is valid.

The following are some example of things you may want to check:

* When accepting cross chain payment for goods and services
  * Ensure the `targetAddress` is your app's payment address
  * Check the chains are supported by your app

```ts
const SUPPORTED_CHAINS = ["ARB", "SOL"];
const isSupportedChain = (chain: string) => SUPPORTED_CHAINS.includes(chain);

export const customTransValidation = async (
  req: SubmitTransRequest
): Promise<string> => {
  const { originChain, targetAddress, targetChain } = req.body;

  // check if the target address is your app's payment address
  if (targetAddress !== (process.env.PAYMENT_ADDRESS as string)) {
    return "invalid target address";
  }

  // check if the chains are supported by your app
  if (!isSupportedChain(originChain)) {
    return "invalid origin chain";
  }

  if (!isSupportedChain(targetChain)) {
    return "invalid target chain";
  }

  // Transaction is valid
  return "";
};
```

## Chain Filtering

Chain filtering is an optional feature that can be enabled by setting the `KIMA_CHAIN_FILTER` environment variable. This will:

* Filter the chains returned by the `/chains` endpoint and therefore the options listed in the React component
* Restricts the allowed chains for `/submit/transfer` and `/submit/swap`, causing a `400` error if the chain is not allowed

It supports two modes:

* `whitelist`: Only chains in the whitelist will be returned.
* `blacklist`: Only chains not in the blacklist will be returned.

This is a JSON object with the following structure:

* `origin`: Filter for the origin chain
  * `mode`: The mode to use. Can be `whitelist` or `blacklist`
  * `chains`: An array of chain short names to filter
* `target`: Filter for the target chain
  * `mode`: The mode to use. Can be `whitelist` or `blacklist`
  * `chains`: An array of chain short names to filter

FIAT rails note:

* Request-level origin chain values can be `CC` and `BANK`.
* Backend normalizes `CC` and `BANK` to `FIAT` before submitting to Kima Chain via `kima-transaction-api`.
* If you want to block FIAT-origin flows robustly, include `CC` and `BANK` in your origin filter.

Example: only `ARB` and `OPT` chains are allowed for the origin and all chains except `TRX` are allowed for the target:

```json
{
  "origin": {
    "mode": "whitelist",
    "chains": ["ARB", "OPT"]
  },
  "target": {
    "mode": "blacklist",
    "chains": ["TRX"]
  }
}
```

Example filtering out FIAT-origin rails (`CC` / `BANK` / normalized `FIAT`):

```json
{
  "origin": {
    "mode": "blacklist",
    "chains": ["CC", "BANK"]
  },
  "target": {
    "mode": "blacklist",
    "chains": ["ARB"]
  }
}
```

The stringified version:

```shell
KIMA_CHAIN_FILTER='{"origin":{"mode":"blacklist","chains":["CC","BANK"]},"target":{"mode":"blacklist","chains":["ARB"]}}'
```

### Compliance

If enabled by supplying the `COMPLIANCE_URL` environment variable, use `GET /compliant/enabled` to check whether compliance is active, and `GET /compliant` to check whether an address meets compliance requirements.

Use this in the frontend to check if an address is not compliant BEFORE the authorization step. When compliance is enabled, `/submit/transfer` and `/submit/swap` return status `403` (Forbidden) for non-compliant addresses.

If you are interested in using compliance, contact us at <support@kima.finance> for more information and the URL to use here.

### KYC

If using the KYC in the widget:

* `GET /uuid` will return the external identifier you need
* `POST /kyc` returns the KYC status for a specific `uuid` verification session

Again, please contact us for more information on how to implement this feature.
