# Overview

### What is a HOT Protocol?

The HOT Protocol is a combination of smart contracts and off-chain services that enables the creation of logic to improve the user experience for crypto asset holders.

We focus on the following areas:

* Chain Abstraction
* Identity Management

Although the protocol is chain-agnostic, its core logic is deployed on the NEAR blockchain due to the convenience of its infrastructure

### What is Chain Abstraction?

Chain abstraction refers to the idea of hiding the complexities and specifics of individual blockchains from users or developers, enabling seamless interaction with multiple blockchains as if they were one unified system

This achieved by implementing OmniBridge to be later used in Near intents.

#### What is OmniBridge?

OmniBridge enables **interoperability** between blockchains by acting as a trusted messenger and token custodian. Instead of deploying new tokens or relying on centralized exchanges, users can move existing tokens across chains, maintaining their value and utility in different blockchain environments.

#### What is Near Intents?

> In NEAR, an `intent` is a high level declaration of what a user wants to achieve. Think of it as telling the blockchain "what" you want to do, not "how" to do it. For example, instead of manually:
>
> * Finding the best DEX for a token swap
> * Calculating optimal routes
> * Executing multiple transactions
>
> You simply express: "I want to swap Token A for Token B at the best price."

<https://docs.near.org/chain-abstraction/intents/overview>

### Identity Management

Currently, there are two main options for storing your assets — and by extension, your "identity":

1. **Centralized exchanges (custodial wallets)**, such as Binance, Bybit, etc.\
   You have access to your account, which implies you *may* have the right to manage your assets. In practice, custodial wallets are subject to regulatory restrictions. On the plus side, they’re as easy to use as logging into your Google Account — often providing a sense of chain abstraction.
2. **Self-hosted wallets** (seed-phrase based).\
   You have full control over your assets, but you bear the responsibility of securely storing your seed phrase (e.g., 12 words written on a piece of paper). This is far less intuitive compared to modern authentication flows we’re used to in everyday apps.

Think of these as the two ends of a spectrum.

We propose a solution that lies in the middle:

* No external "governance" or KYC over your assets
* Full control remains in your hands
* Flexible identity authorization logic (e.g., password + 2FA)
* Transferable identity: for instance, you could sell full access to an account for $20, after which the seller permanently loses control

This approach is implemented using **Multi-Party Computation (MPC)** services.

### What is MPC?

**Multi-Party Computation (MPC)** is a cryptographic technique that allows multiple parties to **jointly compute a function over their inputs** without revealing those inputs to each other.

#### Core Idea

* Several parties each hold private input data.
* They want to compute a result (e.g., a signature, sum, or encrypted value) based on all their inputs.
* MPC enables this computation **without any party revealing their individual input**, and without requiring a trusted third party.

#### Simple Example

Three people want to calculate the **average of their salaries** without disclosing their individual amounts.\
MPC allows them to compute the correct average **without exposing any single salary**.

#### Our application

* **Threshold cryptography**: Splitting private keys across multiple parties (e.g., 2-of-3 signing).
* **Key management**: Secure signing without ever reconstructing the full key.
* **Secure wallets**: non-custodial key control with improved UX and no seed phrase.

<br>


# HOT Omni Balance

## Overview

**HOT Omni Balance** is a cross-chain representations of assets from various networks. It allow unified interaction with tokens across Ethereum-compatible chains, Solana, TON, Bitcoin, Zcash, and more.

HOT Omni Balance standardizes work with tokens secured by:

* [**HOT Omni Bridge** ](/omni-tokens)– supporting EVM-compatible chains, Solana, TON, Stellar
* [**Lite Client Bridges**](https://docs.satos.network/introduction/protocol/protocol-lite-paper) – for trustless Bitcoin and Zcash bridging.

Once bridged, all balances are stored in a **on-chain "database" smart contract**, hosted on the NEAR blockchain. This contract acts as the canonical source of truth for all Omni Token balances, enabling secure and composable interactions.

<figure><img src="/files/JInxCBLITcgTGsWhZonR" alt=""><figcaption></figcaption></figure>

### Trustless Intents

**Intents** are signed user instructions that define specific actions to be executed on the HOT Omni Balance. Intents are signed off-chain by user and executed on-chain by any account, allowing trustless and gasless execution on behalf of the user.

### Intent Types

HOT Protocol currently supports the following core intent types for Omni Tokens:

| Intent Type   | Purpose        | Description                                                        |
| ------------- | -------------- | ------------------------------------------------------------------ |
| `transfer`    | Token transfer | Sends tokens from one user to another.                             |
| `token_diff`  | Swap           | Atomically swaps X of Token A for Y of Token B at a fixed rate.    |
| `mt_withdraw` | Withdrawal     | Withdraws tokens to their native chain via the appropriate bridge. |

All intent executions update the on-chain balance state and may trigger additional events or bridge logic.

***

### JSON Intent Examples

#### 1. Transfer

```json
{
  "intent": "transfer",
  "from": "alice.near",
  "to": "bob.near",
  "token": "nep141:usdc.omni.hot.tg:eth",
  "amount": "1000000",
  "nonce": "1749735276000003203"
}
```

#### 2. Token Swap (token\_diff)

```json
{
  "intent": "token_diff",
  "diff": {
    "nep141:usdc.omni.hot.tg:eth": "-1000000",
    "nep141:dai.omni.hot.tg:eth": "995000"
  },
  "referral": "intents.tg",
  "nonce": "1749735276000003204"
}
```

#### 3. Withdraw (mt\_withdraw)

```json
{
  "intent": "mt_withdraw",
  "token": "btc.omni.hot.tg:mainnet",
  "amount": "100000",
  "recipient": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
  "nonce": "1749735276000003205"
}
```

Each intent must be accompanied by a valid cryptographic signature using the signer’s chain-specific format.

***

### Supported Signature Standards

To enable seamless integration across chains, HOT Omni Balance supports native signature formats per network:

| Network        | Signature Format                   | Standard                |
| -------------- | ---------------------------------- | ----------------------- |
| Ethereum / EVM | `eth_sign`, `eth_signTypedData_v4` | EIP-191, EIP-712        |
| Solana         | Base58 Ed25519                     | Solana `Message`        |
| NEAR           | Ed25519 (NEP-413)                  | `signed_message`        |
| TON            | TL-B with `wallet v4/v5`           | Custom signature schema |
| Stellar        | XDR-auth message                   | SEP-0010                |

This allows users to sign intents using their native wallets without needing additional infrastructure.

<figure><img src="/files/xTblpGX4Ic3csQsSl99K" alt=""><figcaption></figcaption></figure>

### Swap Architecture

Swaps (e.g., `token_diff`) in HOT Protocol are designed to be flexible and modular. Execution can be handled in multiple ways:

1. **Solvers**\
   External entities (like market makers or bots) who scan the mempool or listen to intent APIs, validate signature + price, and fulfill the swap. They may:
   * Hedge externally (on CEX/DEX).
   * Route liquidity internally.
2. **On-chain AMM** *(Optional)*\
   A fallback mechanism for direct swaps without a solver. This provides a trustless execution path for certain pools.
3. **Intents-based Orderbooks** *(Experimental)*\
   Users can post signed limit orders (intents) to be matched by anyone — a novel decentralized orderbook using HOT Omni Tokens.

### Chain Abstraction dApps

Thanks to HOT Omni Balance intent model, developers can build **Chain Abstraction** apps that:

* Interact with assets from multiple chains via a single interface.
* Use one signer identity to control assets from Solana, Ethereum, TON, etc.
* Stay gasless: all fees can be subsidized or paid via token abstraction.

<figure><img src="/files/3Mww2VJIRIzlIUHGqM8E" alt=""><figcaption></figcaption></figure>

### SDK

{% embed url="<https://github.com/hot-dao/omni-sdk>" %}


# HOT Bridge

## Abstract

**HOT Bridge** is a protocol for minting omni-assets within the **HOT OMNI Balance** smart contract, backed 1:1 by assets locked on native networks (e.g., Solana, Ethereum, TON). These assets can be transferred and swapped within inside **HOT OMNI Balance**, and redeemed for their original native tokens at any time.

### Architecture

Omni bridge consists of:

* Locker contracts, one per each supported chain
  * Store native assets
  * Implement api for deposit validation by HOT Protocol validators
  * Process deposit/withdrawals of native assets
* HOT OMNI Balance, contract on NEAR Protocol
  * Store, Mint and Burn omni-assets.
  * Implement api for withdrawal validation by HOT Protocol validators
  * Implement NEP-254 Multitoken standard, so omni-assets can be used by any smart contract on NEAR Protocol. This is useful in a higher level tools like [Near Intents](https://docs.near.org/chain-abstraction/intents/overview)
* HOT Bridge - list of instructions within client sdk for depositing and withdrawing assets on HOT Omni Balance.
* HOT Protocol - MPC networks of validators that validate cross-chain messages.

### Deposit flow

<figure><img src="/files/zlffPhJAf9NxRhFZaNKt" alt=""><figcaption></figcaption></figure>

1. **Transfer liquidity to the locker contract**\
   How this done exactly depends a specific chain. It can be either token transfer to the contract address, or tokens attached to the call.

   After deposit, locker contract save deposit data into the contract state generate a unique `nonce`.
2. **Generate Proof**\
   The user call HOT MPC networks, providing nonce and deposit arguments. Each MPC node call view method of locker contract to verify that this deposit actually exist.
3. **Mint omni-token**\
   The user execute `deposit` method on Omni Balance contract, providing nonce, signature and deposit arguments. The Omni Balance contract verify that signature is valid and nonce have never been used before and mints omni-tokens.

### Withdraw flow

<figure><img src="/files/nkSgQimo0XDCOMWqxoVN" alt=""><figcaption></figcaption></figure>

* **Burn omni-asset**\
  After withdrawal, omni balance contract burns omni-token, save withdrawal data into the contract state and generate a unique `nonce`.
* **Generate Proof**\
  The user call HOT MPC networks, providing nonce and withdrawal arguments. Each MPC node call view method of omni balance contract to verify that this withdrawal actually exist.
* **Get token on target chain**\
  The user execute `withdraw` method on locker contract, providing nonce, signature and withdrawal arguments. The locker contract verify that signature is valid and nonce have never been used before and transfers native tokens to receiver.

## **Omni Bridge API**

### `deposit` method on `v2_1.omni.hot.tg` contract on NEAR Blockchain

Args:

```
receiver_data: AccountId/String
receiver_id: String
chain_id: u64
contract_id: String
amount: U128
nonce: U128
signature: Signature
```

* `signature` - MPC **ECDSA** signature of `hash(rlp_encode(receiver, chain_id, token_address, amount, nonce))`
* `receiver` - 32 bytes = `hash(receiver_data)`. Some smart contracts work with a fixed par memory size, so receiver\_id is always 32 bytes. The receiver\_data format can be extended to work with the intents contract without requiring the data format on the locker contracts to be changed.
* `nonce` - nonce, that have been generated inside Locker Contract
* `amount` - deposit amount
* `contract_id` - token contract address bytes in base58
  * on TON: `Cell(address).to_bytes()`
  * on Stellar: `Asset("USDC", "PUBLIC_NETWORK_PASSPHRASE").to_xdr_bytes()`
  * on EVM: `bytes.from_hex(contarct address)`
  * on Solana: Token Mint Address
* `chain_id` - chain id
  * EVM chain id for all EVM Chain
  * TON = 1111
  * SOLANA = 1001
  * STELLAR = 1100
  * TRON = 999


# Calculate token omni address

When you deposit a token via HOT Bridge on NEAR Intents, its address will be deterministically altered from the original on-chain format. To compute the omni format, you can use the TypeScript library `@hot-labs/omni-sdk`.

<table><thead><tr><th width="148.28125">Types</th><th width="397.05859375">Format</th><th>How calculate</th></tr></thead><tbody><tr><td>Onchain</td><td>any chain-specific format</td><td></td></tr><tr><td>HOT Bridge</td><td><code>v2_1.omni.hot.tg:</code><strong><code>CHAIN</code></strong><code>_</code><strong><code>BASE58</code></strong></td><td><code>utils.toOmni</code></td></tr><tr><td>NEAR Intents</td><td><code>nep245:v2_1.omni.hot.tg:</code><strong><code>CHAIN</code></strong><code>_</code><strong><code>BASE58</code></strong></td><td><code>utils.toOmniIntent</code></td></tr></tbody></table>

## Stellar tokens

Stellar has two types of tokens:

1. **Classic Assets** (G-address issuer): Use `Asset.contractId()` to derive the Soroban contract ID
2. **Native Soroban Contracts** (C-address): Use the contract address directly

### Classic Assets (G-address issuer)

In the Stellar blockchain, there's an additional complexity. The blockchain features high-level Assets, accessible through an Issuer contract and symbol. However, HOT Bridge interacts with the token contract instead. This contract can be obtained via `asset.contractId(Networks.PUBLIC)` and this address must be converted to an HOT Bridge address.

```typescript
import { utils, Network, HotBridge } from "@hot-labs/omni-sdk";
import { Asset, Networks } from "@stellar/stellar-sdk";

const main = async () => {
  // symbol + issuer
  const asset = new Asset("CETES", "GCRYUGD5NVARGXT56XEZI5CIFCQETYHAPQQTHO2O3IQZTHDH4LATMYWC");

  // Convert contractId to omni address (NOT ISSUER!)
  const omniAddress = utils.toOmniIntent(Network.Stellar, asset.contractId(Networks.PUBLIC));
  console.log(omniAddress);

  // How to convert omni address to asset?
  const hotBridge = new HotBridge({});
  const [stellarChainId, tokenContractAddress] = utils.fromOmni(omniAddress).split(":"); // 1100:ADDRESS

  // Get asset from contract id
  const assetFromOmniId = await hotBridge.stellar.getAssetFromContractId(tokenContractAddress);

  // Check if the asset is the same
  console.log(assetFromOmniId.contractId(Networks.PUBLIC) === asset.contractId(Networks.PUBLIC));
};

main();
```

### Native Soroban Contracts (C-address)

```typescript
import { utils, Network } from "@hot-labs/omni-sdk";

// Use the contract address directly
const contract = "CBIJBDNZNF4X35BJ4FFZWCDBSCKOP5NB4PLG4SNENRMLAPYG4P5FM6VN";
const omniAddress = utils.toOmniIntent(Network.Stellar, contract);
console.log(omniAddress);
```


# Security

List of audits for HOT Bridge, Intents, MPC Node core & Validation module could be found in [Google Drive](https://drive.google.com/drive/folders/1eNHI_GKsbmMSjeCENRklvtVh8imGSUvy?usp=sharing).

Please report bugs and security vulnerabilities via [Hackenproof](https://hackenproof.com/programs/near-intents) bug bounty program.

For any AML/CTF (Anti-Money Laundering and Counter-Terrorism Financing) related requests, please refer to our [AML Portal](https://aml.near-intents.org/).


# MPC Wallet

### Default authorization method

*To be added*

### 2FA

*To be added*

### Add New Authorization Method

*To be added*


# Signature generation via MPC

### Signature Generation

The primary use of the MPC network for us is secure signature generation.

Currently, we support the following signature formats:

* **ECDSA** — used in Bitcoin, EVM chains, BNB, Polygon
* **EdDSA** — used in Solana, NEAR, Polkadot

The MPC network is developed in collaboration with **NEAR One**.\
Some details can be found [here](https://docs.near.org/chain-abstraction/chain-signatures).

While on-chain smart contracts are used for signature generation on the NEAR blockchain, we focus primarily on the **off-chain signing API**, which offers higher bandwidth and lower latency.

### What is an HOT account?

As we work with chain agnostic identities, we have to explicitly define what identity is.

Identity is a `wallet_id: [u8; 32]` , some 32 bytes, which is a hash of *some* `uid`

<figure><picture><source srcset="/files/BlbV1y1tlHiQRXEyiflG" media="(prefers-color-scheme: dark)"><img src="/files/BlbV1y1tlHiQRXEyiflG" alt=""></picture><figcaption></figcaption></figure>

Suffice to say at the moment, that `uid` coming from a random source.

### Key Derivation Function

We have to associate a key pair with an identity.

All accounts are created on top of MPC network. The MPC network has its own master key, from which all keys are derived. This process is described as Key Derivation Function:

<figure><img src="/files/GMrREMtmIrVBaIUc5Aze" alt=""><figcaption></figcaption></figure>

Thus, a set of public keys associated with `wallet_id` comes from `uid` too.

Important note: at any point of time no one knows MPC's `Secret Key` , nor `Derived Secret Key` , though `Public Key` and its derivations are well known.

Nevertheless, it is still possible to sign a message with `Derived Secret Key` , thanks to MPC technology.

But, if one wants to sign a message on behalf of specified `uid`, they have to prove ownership of that `uid` – which is the same of proving ownership of `wallet_id`, which is the identity.

### Authorization of Signature Generation

We must ensure that only messages **explicitly authorized by the user** are signed — not arbitrary requests.

Here's the abstract authorization flow, which can be used for any purpose. We will look at the specific examples (bridge use-case, mutlichain usage) later.

<figure><img src="/files/mZwOyvxi97VncsevwEQU" alt=""><figcaption></figcaption></figure>

1. **User sends a signature request to the MPC network**

The off-chain signing API accepts the following data:

```
JsonValue {
  uid: [u8; 32],
  message: [u8],
  proof: JsonValue
}
```

* `uid` – unique identifier for the user. Then we simply calculate `wallet_id = hash(uid)`
* `message` – message to be signed
* `proof` – data used to authorize the signature for the given uid<br>

2. **MPC Network before initiating a signing algorithm, starts the validation procedure**

Formally, the interpretation of `proof` is determined by each MPC node. In practice, all nodes follow a unified validation process

3-4. **Get authroization methods for the wallet**

We ask an account registry, which stores authorization methods for each `wallet_id`\
In theory, arbitrary logic can be placed in authorization method. In practice it's a contract on some blockchain which implements specific API.

5. **Check each authorization method**

For each validation method we call a view method of the specified contract on its chain. In return we receive true/false as a result whether validation method passed.

6-7. **Proceed with the signature generation**

If all verifiaction methods succeeded, we move on to the cryptographic protocol for message signing.

8. **User get desired signature**


# MPC API

Public RPCs

* `https://rpc1.hotdao.ai`

## 1/2. Create wallet `/create_wallet`

<figure><img src="/files/0KpatzePybYq5gzikV7x" alt=""><figcaption></figcaption></figure>

#### 1. Generate a new Ed25519 keypair

Create a new keypair using your preferred cryptographic library (e.g., `pynacl`, `ed25519`).

* The **public key** becomes `wallet_derive_public_key`.
* You will use the **private key** to sign a proof of ownership.

#### 2. Get `derive` and `wallet_id` from the `wallet_derive_public_key`

```plaintext
derive = sha256(public_key_bytes)
wallet_id = base58_encode(sha256(sha256(public_key_bytes)))
```

This ensures every wallet is uniquely tied to its public key, and anyone can re-derive it for validation.

#### 3. Construct the proof message

You need to prove first authorization rule by signing a specific message.

```
"CREATE_WALLET:{wallet_id}:{auth_account_id}:{metadata}:{auth_msg}"
```

* `wallet_id`: the one you just derived.
* `auth_account_id`: authorization contract account id .g., `"keys.auth.hot.tg"`.
* `msg`: a JSON string that will be include in `on_auth_add(..)` method

Example `msg` string for `keys.auth.hot.tg`:

```json
{"public_keys":["your_base58_public_key"],"rules":[]}
```

#### 4. Sign the hashed message

Hash the **proof message** string with SHA-256 and sign the hash using your `wallet_derive_public_key` private key. Encode the signature in base58 — this becomes the `signature` field in the request.

#### 5. Assemble the full request

Your JSON request to the API should include:

* `wallet_id`: the value you derived from the public key.
* `wallet_derive_public_key`: your base58-encoded public key.
* `signature`: the base58-encoded signature of **proof message**
* `key_gen`: MPC Key generation , now always = 1.
* `auth`: containing:
  * `msg`: JSON string that will be include in `on_auth_add(..)` method
  * `auth_account_id`: typically `"keys.auth.hot.tg"`

Example

```bash
curl 'https://rpc1.hotdao.ai/create_wallet' \
  -H 'accept-language: en-US,en;q=0.9' \
  -H 'content-type: application/json' \
  --data-raw '{
    "wallet_derive_public_key": "9buZSPUUSkzkYdaCMWh4vNAgz2Yi84VGW6Pqf5hegHCn",
    "wallet_id": "5Z5x7arDYpr4AM2BnLMPHPQ5nW6ryknBcbXSQGiQQcDK",
    "public_key": "9UWi6hXT31bV29LRQdX5gLKNiWcRfeARan7oiqHjHmDt",
    "signature": "24cEDwicHLD6Z7WMRnXa5WdfniRCxPwAA4r6f3WRGNQY9q7CaRAiTkgNo16uBRmy365obFprUj8C6giJiZyqmLqc",
    "key_gen": 1,
    "auth": {
      "msg": "{\"public_keys\":[\"9UWi6hXT31bV29LRQdX5gLKNiWcRfeARan7oiqHjHmDt\"],\"rules\":[]}",
      "auth_account_id": "keys.auth.hot.tg",
    }
  }'
```

## 2/2.Sign massage `/sign`

<figure><img src="/files/RHfNGS8L3gLAEhewS1o7" alt=""><figcaption></figcaption></figure>

our JSON request to the API should include:

* `wallet_derive`: the value you derived from the public key.
* `message`: your base58-encoded massage that need to be signed (hash(msg) for evm chains, raw massage for Solana)
* `curve_type`:
  * 0 - EdDSA
  * 1 - Ecdsa
* `user_payloads`: list of strings, that will be used in hot\_verify(..) method of your auth contracts. They must be in the same order as auth methods in MPC registed:

  ```
  near view mpc.hot.tg get_wallet {"wallet_id":"WALLET_ID"}
  ```


# HOT Kit

HOT Kit is a powerful library for blockchain and omni-balance management. It supports both browser-based dApps and servers. Key features include

### 1. Multi-chain connector

HOT Kit lets users connect their own wallets to your site or log in via Google. It's great for onboarding web2 users into your app. With WalletConnect support, any mobile wallet can be connected effortlessly.

<figure><img src="/files/oesWBzQhDX1EUe8MZ2ML" alt=""><figcaption></figcaption></figure>

* **NEAR Connector**\
  WC, HOT Wallet, Meteor, Intear, MyNearWallet, etc
* **EVM Connector**\
  WC, HOT Wallet, MetaMask and all browser wallets
* **Solana Connector**\
  WC, Hot Wallet, Phantom and all browser wallets
* **TON Connector**\
  HOT Wallet, TonKeeper and all web/mobile wallets
* **Stellar Connector**\
  HOT Wallet, Freighter
* **TRON Connector**\
  TronLink (WC soon)
* **Cosmos Connector**\
  WC, Keplr, Leap
* **Connect via Google (experimental)**\
  Users receive addresses for all networks mentioned above via their Google account. The user's Google Wallet operates through HOT MPC and will be accessible after authorization at <https://app.hot-labs.org>.<br>

```typescript
import { HotConnector } from "@hot-labs/kit";
import { defaultConnectors } from "@hot-labs/kit/defaults";
import google from "@hot-labs/kit/hot-wallet";
import cosmos from "@hot-labs/kit/cosmos";

export const kit = new HotConnector({
  apiKey: "Get on https://pay.hot-labs.org/admin/api-keys for free",
  connectors:  [...defaultConnectors, cosmos(), google()],
  walletConnect: { // Get from dashboard.reown.com
    projectId: "3cbf324S21f18648ed6153e2c324l2cf",
    metadata: {
      name: "App",
      description: "Awesome App",
      url: "https://app.com",
      icons: ["https://app.com/logo.png"],
    },
  },
});
```

### 2. User portfolio

Users can view their token balances in connected wallets, and these balances are also available for you in the code.

<figure><img src="/files/6OZc90ytqlWcrLYGGvhl" alt=""><figcaption></figcaption></figure>

```typescript
kit.openProfile() // to open popup with profile

// Get balances
kit.walletsTokens.forEach(({ wallet, token, balance }) => {
   console.log(wallet.address, `${token.float(balance)} ${token.symbol}`)
})

// Refresh balances
const evmWallet = kit.evm // if connected or null
await kit.fetchTokens(evmWallet)

```

### 3. Exchange tokens

<figure><img src="/files/ZKcUyNkmYAWpgxVe2xCt" alt=""><figcaption></figcaption></figure>

```typescript
kit.openBridge() // to open popup with bridge

// Or use manual
const review = await kit.exchange.reviewSwap({ .. }) // get qoute
await kit.exchange.makeSwap(review) // do it!
```


# Installation

{% hint style="info" %}
To fully utilize the features of HOT Kit, obtain a free API key from the platform at [pay.hot-labs.org/admin/api-keys](https://pay.hot-labs.org/admin/api-keys).
{% endhint %}

### Client-side setup

`npm install @hot-labs/kit`

HOT Kit require you to install **node-polyfills** and react to work, for **vite** you need to complete the following extra steps:

`npm install vite-plugin-node-polyfills @vitejs/plugin-react`

Then in your `vite.config.ts` add this plugins:

```ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { nodePolyfills } from "vite-plugin-node-polyfills";

export default defineConfig({
  plugins: [nodePolyfills(), react()],
});
```

Also HotConnector use React and ReactDOM to render UI, you should install this deps to start work:

```
npm install react react-dom
```

And now your can initialize connector:

```ts
import { HotConnector } from "@hot-labs/kit";
import { defaultConnectors } from "@hot-labs/kit/defaults";

const connector = new HotConnector({
  connectors: defaultConnectors,
  apiKey: "Get on https://pay.hot-labs.org/admin/api-keys for free",

  // optional get on https://dashboard.reown.com
  walletConnect: {
    projectId: "1292473190ce7eb75c9de67e15aaad99",
    metadata: {
      name: "Example App",
      description: "Example App",
      url: window.location.origin,
      icons: ["/favicon.ico"],
    },
  },
});
```

### Nodejs setup

```
npm install @hot-labs/kit
```

To work server-side, you cannot use the HotConnector class, but you can use components from the library available via `@hot-labs/kit/core`. Additional build configuration or polyfills are not needed. Instead of using a UI to connect an external wallet, you need to directly create a wallet using your private key.

```typescript
import { tokens, Network } from '@hot-labs/kit/core';
import { NearWallet } from '@hot-labs/kit/near';

// optional, refresh tokens and rates in background process
tokens.startTokenPolling()

// Force refresh tokens list
tokens.refreshTokens()

const privateKey = Buffer.from(process.env.PRIVATE_KEY, 'hex')
const wallet = await NearWallet.fromPrivateKey(privateKey, process.env.SIGNER_ID);

const usdc = tokens.get("native", Network.Base)
const balances = await wallet.fetchBalances() as Record<string, bigint>
console.log(`${usdc.float(balances[usdc.id])} ${usdc.symbol}) // 2.3 USDC

```


# Manage connected wallets

The `HotConnector` class implements communication between different components of the library, maintaining the state of connected wallets, balances, and active transactions. Let's look at how to use it:

```typescript
const kit = new HotConnector({ ... }) 

// Use wallet.type to specify chain: WalletType.EVM/NEAR/TON/Stellar/Solana/Cosmos
kit.onConnect(({ wallet }) => {})

// if user disconnect wallet
kit.onDisconnect(({ wallet }) => {})

const wallet = await kit.connect() // or pass WalletType.EVM
await kit.disconnect(wallet) // or just WalletType.EVM/wallet.type
```

{% hint style="info" %}
HotConnector uses MobX to provide reactive state out of the box. In a separate article, you can learn how to integrate HOT Kit with React.
{% endhint %}

### Wallet instance

Regardless of the connected chain or wallet, you receive a consistent interface, allowing you to:

```typescript
interface OmniWallet {  
  readonly address: string; // chain-specific address
  readonly publicKey?: string; // chain-specific publicKey (hex/base58)
  readonly omniAddress: string; // omni address (determistic from address)
  readonly type: WalletType; // Type of wallet (EVM/TON/Solana/NEAR/Stellar/Cosmos)
  
  // tx is chain-specific object, this method will execute transaction and return hash
  async sendTransaction(tx: any): Promise<string> 

  // How many network fee you should pay to make transfer tx
  async transferFee(token: Token, receiver: string, amount: bigint): Promise<ReviewFee>

  // Transfer transaction (common arguments for any chain)
  async transfer(args: { 
     token: Token; 
     receiver: string; 
     amount: bigint; 
     comment?: string; 
     gasFee?: ReviewFee 
  }): Promise<string>

  // Balances
  async fetchBalance(chain: number, address: string): Promise<bigint>
  async fetchBalances(chain: number): Promise<Record<string, bigint>>

  // Это методы нужны для работы с омни балансами, подробнее в Intents builder
  async signIntents(intents: Record<string, any>[], options?: { nonce?: Uint8Array; deadline?: number; signerId?: string }): Promise<Commitment>
  async auth<T = string>(intents?: Record<string, any>[], options?: { domain?: string; signerId?: string; customAuth?: (commitment: Commitment, seed: string) => Promise<T> }): Promise<T>
  async waitUntilOmniBalance(need: Record<string, bigint>, receiver = this.omniAddress, attempts = 0)
}
```


# Manage tokens and balances

HOT Kit significantly simplifies token management, providing access to token information across various networks, current exchange rates in USD, and balances of connected wallets. Let's take a closer look at the tokens manager:

### Tokens repository

Each token has a unique ID, which is structured as `chainID:tokenAddress`. You can retrieve a specific token's class using `tokens.get`. This class offers several useful methods for formatting the balance according to the token's decimals.

```typescript
import { tokens, chains, Network } from '@hot-labs/kit'

// The repository chains contains data on all popular blockchains.
const baseChain = chains.get(Network.Base)

// The tokens repository contains a list of primary tokens, 
// which are supported for exchange and display in portfolios.
const ethOnBase = tokens.get("native", Network.Base)

// Converts an int to a float using the token's decimals.
ethOnBase.float(10_000_000n)

// Converts a number to an integer using decimals.
ethOnBase.int(10)

// Actual 0.01 ETH in dollars
console.log(`USD: ${ethOnBase.float(10n ** BigInt(ethOnBase.decimals - 2)) * ethOnBase.usd}`)

// IMPORTANT:
// ID of token is combination of chain id and address
// Any native token has address === 'native'
token.id === `${token.chain}:${token.address}`
```

### Refresh tokens and rates

If you are working with the `HotConnector` class, the current list of tokens and balances are automatically updated. If you received a token through `tokens.get`, its USD rate will be updated automatically, meaning any access to `token.usd` will give you the current rate within a 5-minute interval.

If you are working with Node.js or do not wish to use `HotConnector`, you can explicitly initialize automatic balance updates or request a forced update of the entire repository.

```typescript
tokens.startTokenPolling(interval?: number) // default inverval 2 minutes
tokens.refreshTokens() // or force refresh
```


# Transfer omni token

When working with Omni balances, the two most common use cases are exchange and transfer. Let’s take a look at how to implement sending an Omni token from your wallet to another address.

{% hint style="info" %}
You can find a fully working example here:\
<https://github.com/hot-dao/kit/blob/main/examples-node/transfer.ts>
{% endhint %}

#### 1. Connect wallet

First, if you are using Node.js rather than a browser, you need to initialize the wallet using a private key. For example:

```typescript
import { NearWallet } from "@hot-labs/kit/near";

const privateKey = Buffer.from(process.env.PRIVATE_KEY, 'hex')
const wallet = await NearWallet.fromPrivateKey(privateKey, process.env.ACCOUNT_ID);
```

For a browser-based application, it is sufficient to request a wallet from the HOT Connector:

```typescript
import { HotConnector } from "@hot-labs/kit"
import { defaultConnectors } from "@hot-labs/kit/defaults"
const kit = new HotConnector({ connectors: defaultConnectors })
const wallet = await kit.connect(); // Open UI
```

#### 2. Recipient

Now let’s create the recipient address. Since you are sending Omni tokens from one account to another, **you cannot simply use the recipient’s on-chain address**. Omni balances are stored on addresses of a different format, so first, we need to create a Recipient object:

```typescript
import { Recipient, Network } from "@hot-labs/kit/core";

// Real onchain evm address:
const recipient = await Recipient.fromAddress(Network.Eth, "0x...");
```

Recipient is a convenient class that computes the Omni address from your on-chain address. This class has three fields: `type`, `address`, and `omniAddress`.

#### 3. Build and execute intent

Now we are ready to create our **transfer intent** and send **OMNI NEAR** from our wallet to an EVM wallet (in Omni balance):

```typescript
import { OmniToken } from "@hot-labs/kit/core";

const hash = await wallet
  .intents() // create Intents Builder
  .transfer({
    recipient: recipient.omniAddress,
    token: OmniToken.NEAR, // ID like -4:omniTokenAddress
    amount: 10,
  })
  .execute(); // execute transfer intent

console.log("10 NEAR Transfer Hash:", `https://hotscan.org/transaction/${hash}`);
```

Each wallet in **HOT Kit** has a special **IntentsBuilder**, which allows you to create any action with your OMNI balance. The commands chain usually ends with a call to **execute**, which signs the created intents and then sends them to the blockchain (**for free!**).

As a result, you receive a transaction hash, which can be tracked on HOT Scan. Example transaction: [https://hotscan.org/transaction/4cYXDkgofecfPKWvjeAnqs1VtRP1PbnLe](https://hotscan.org/transaction/4cYXDkgofecfPKWvjeAnqs1VtRP1PbnLeGLZnKdoTmnT)

### Why I need transfer to omni?

Transfers within OMNI are **very fast and completely free**. You don’t need to worry about which blockchain the recipient uses or how much to spend on fees. However, if you need to send OMNI tokens directly to a specific on-chain wallet, the next chapter on withdrawing OMNI tokens will guide you.


# Withdraw omni token

The second use case when working with Omni is withdrawing tokens to the blockchain. Let’s look at an example of how this can be implemented via an exchange.

{% hint style="info" %}
You can find a complete working example here:

<https://github.com/hot-dao/kit/blob/main/examples-node/withdraw.ts>
{% endhint %}

<pre class="language-typescript"><code class="lang-typescript">import { Recipient, tokens, OmniToken, Network, Exchange } from "@hot-labs/kit/core";
import { NearWallet } from "@hot-labs/kit/near";

const exchange = new Exchange();
const wallet = await NearWallet.fromPrivateKey(Buffer.from(PRIVATE_KEY), SIGNER_ID);
const recipient = await Recipient.fromAddress(Network.Tron, "TTB...");

// We want to exchange OMNI USDT to TRC20 USDT
const omniUSDT = tokens.get(OmniToken.USDT);
const realTRONUSDT = tokens.get("TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", Network.Tron);

// Get qoute for exchange
const review = await exchange.reviewSwap({
    sender: wallet,
    
    // Who receive TRC20 USDT
    recipient: recipient,
    
    // If the exchange does not occur, USDT will automatically be returned to our wallet.
    refund: wallet,

    from: omniUSDT, // OMNI TOKEN
    to: realTRONUSDT, // TRON TOKEN

    // Send 10 USDT
    amount: omniUSDT.int(10),
    type: "exactIn",
    
    // Since it's not just an output but an exchange for another token, 
    // it's important to account for slippage!
    slippage: 0.01, // 1% slippage
    
    logger: console,
});


// Check how many tokens the recipient will receive. 
// Remember to consider that the exchange rate might be unfavorable!
console.log("From", review.from.float(review.amountIn), review.from.symbol);
console.log("To", review.to.float(review.amountOut), review.to.symbol);

// The review object includes everything needed to proceed with this output. 
// The makeSwap function will transfer tokens from your wallet, 
// but note that the exchange process will take more time to complete.
const { processing } = await exchange.makeSwap(review);

// Start a separate method to monitor and wait for the exchange result.
const resultReview = await processing?.();

<strong>// Funds have now arrived!
</strong>console.log(resultReview);
</code></pre>


# Authorization flow

#### JWT Authentication

The `auth()` method allows you to authenticate a wallet and receive a JWT token. This is useful for backend authentication and verifying wallet ownership.

**How it works:**

1. Opens a UI popup asking the user to sign a message
2. Generates a random seed and creates a cryptographic nonce
3. Signs intents (or empty array) with the nonce
4. Sends the signed commitment to the API
5. Returns a JWT token string

**Basic Usage:**

```typescript
// Get JWT token for authentication
const wallet = wibe3.priorityWallet; // or any connected wallet
if (wallet) {
  const jwt = await wallet.auth();
  console.log("JWT token:", jwt);

  // Use JWT for backend authentication
  // Example: send to your backend API
  await fetch("https://your-api.com/authenticate", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${jwt}`,
      "Content-Type": "application/json",
    },
  });
}
```

**Auth with Intents (Optional):**

You can optionally pass intents to be signed during authentication:

```typescript
// Auth with intents (optional)
const intents = [{
   intent: "transfer",
   recipient: "petya.near",
   token: OmniToken.USDC,
   amount: 10,
}];

const jwt = await wibe3.priorityWallet.auth(intents);
console.log("JWT with signed intents:", jwt);
```

**Validate JWT Token:**

You can validate a JWT token using the API:

```typescript
import { api } from "@hot-labs/kit";

// Validate JWT token
const isValid = await api.validateAuth(jwt);
console.log("Token is valid:", isValid);
```

**Complete Example:**

```tsx
import { observer } from "mobx-react-lite";
import { HotConnector } from "@hot-labs/kit";

const wibe3 = new HotConnector({ ... });

const App = observer(() => {
  const handleAuthenticate = async () => {
    const wallet = wibe3.priorityWallet;
    if (!wallet) return alert("Please connect a wallet first");

    try {
      // Get JWT token
      const jwt = await wallet.auth();

      // Store JWT (e.g., in localStorage or send to backend)
      localStorage.setItem("authToken", jwt);

      // Use JWT for authenticated API calls
      const response = await fetch("https://your-api.com/user/profile", {
        headers: { Authorization: `Bearer ${jwt}` },
      });

      const userData = await response.json();
      console.log("User data:", userData);
      alert("Authentication successful!");
    } catch (error) {
      console.error("Authentication failed:", error);
      alert("Authentication failed");
    }
  };

  return (
    <div>
      <button onClick={handleAuthenticate}>Authenticate & Get JWT</button>
    </div>
  );
});
```

**Important Notes:**

* The `auth()` method opens a UI popup that requires user interaction to sign the message
* The JWT token is generated server-side and returned after successful signature verification
* The token can be used for backend authentication to verify wallet ownership
* The authentication process is safe - it only signs a message, not a transaction
* You can optionally pass intents to be signed during authentication


# Connect via Google (wip)

<figure><img src="/files/Pk33YBf4riaHuTjvCN2I" alt=""><figcaption></figcaption></figure>

\
Demo video (upload to YouTube):

{% file src="/files/w0uAVXTV44mYqNSten2E" %}


# Exchange flow (wip)

С помощью


# Omni balances (wip)

More specific technical details about technology here:

{% content-ref url="/pages/D9jaeMLS20JI1vDHfPNF" %}
[HOT Omni Balance](/hot-omni-balance)
{% endcontent-ref %}


# Intents builder (wip)

More specific technical details about technology here:

{% content-ref url="/pages/D9jaeMLS20JI1vDHfPNF" %}
[HOT Omni Balance](/hot-omni-balance)
{% endcontent-ref %}


# Mint NFT via HOT Craft

#### NFT Mint Example (Omni Chain / Intents)

Mint NFTs using `authCall` intent. This example shows how to mint multiple NFTs in a batch:

```typescript
interface MintMsg {
  msg: string; // trading address
  token_owner_id: string;
  token_id: string;
  token_metadata: {
    reference?: string;
    description: string;
    title: string;
    media: string;
  };
}

interface NFT {
  title: string;
  description: string;
  image: string;
  reference?: string;
}

const kit = new HotConnector({ ... })

async function mintNFTs(collection: string, nfts: NFT[], totalSupply: number) {
  const wallet = kit.priorityWallet
  if (!wallet) throw new Error("No wallet connected");
  
  const tradingAddress = wallet.omniAddress;
  const builder = kit.intentsBuilder(wallet)

  // Calculate total storage deposit needed for all NFTs
  let totalDeposit = 0n;
  const intents: any[] = [];

  for (let i = 0; i < nfts.length; i++) {
    const nft = nfts[i];
    const msg: MintMsg = {
      msg: tradingAddress,
      token_owner_id: "intents.near",
      token_id: (totalSupply + i).toString(),
      token_metadata: {
        reference: nft.reference || undefined,
        description: nft.description || "",
        title: nft.title,
        media: nft.image,
      },
    };

    // Calculate deposit size based on metadata size
    // Formula: (JSON string length * 8 bits) / 100,000 * 10^24 yoctoNEAR
    const metadataSize = JSON.stringify(msg.token_metadata).length;
    const size = BigInt((metadataSize * 8) / 100_000) * BigInt(10 ** 24);
    totalDeposit += size;

    // Create auth_call intent
    builder.authCall({
      attachNear: size.toString(),
      contractId: collection,
      msg: JSON.stringify(msg),
      tgas: 50,
    });
  }

  // Execute all intents
  return await builder.execute();
}

// Usage example
const nfts: NFT[] = [
  {
    title: "My NFT #1",
    description: "First NFT in collection",
    image: "https://example.com/nft1.png",
    reference: "https://example.com/nft1.json",
  },
  {
    title: "My NFT #2",
    description: "Second NFT in collection",
    image: "https://example.com/nft2.png",
  },
];

// Deploy contract with 100 max supply and mint 2 nft
await mintNFTs("my-nft-collection.near", nfts, 100);
```

#### NFT UI Recommendation: Trade On HOT Craft

When working with NFTs in your UI, it's **recommended to add a "Trade On HOT Craft" button** that links to the HOT Craft marketplace:

```typescript
import { observer } from "mobx-react-lite";

const NFTComponent = observer(() => {
  return (
    <div>
      {/* Your NFT display */}
      <div>
        <img src={nft.image} alt={nft.title} />
        <h3>{nft.title}</h3>
        <p>{nft.description}</p>
      </div>

      {/* Recommended: Trade On HOT Craft button */}
      <a href="https://hotcraft.art/" target="_blank" rel="noopener noreferrer">
        Trade On HOT Craft
      </a>
    </div>
  );
});
```

**Why add this button?**

* Provides users with a marketplace to trade their NFTs
* Improves user experience by offering trading functionality
* Connects your app with the HOT Craft ecosystem

<br>


