---
title: Quickstart
description: "A complete cross-chain swap: quote, deposit, and settlement."
---
This builds one USDC transfer from Arbitrum to Solana. The same four calls cover every pair the protocol supports.
## Before you start
Keyless requests work, but they are rate limited per IP and priced with extra spread. See [API keys](/integration/api-keys).
Install the SDK, or generate stubs from `api.proto`. See [Transports](/integration/transports).
```bash
npm install @mayanfinance/hular-sdk
```
```bash
for f in hular/v1/api.proto hular/v1/ratelimit.proto google/api/annotations.proto google/api/http.proto; do
curl --create-dirs -o "$f" "https://docs.hular.dev/proto/$f"
done
```
## 1. Connect
```ts
import { createHularClient } from "@mayanfinance/hular-sdk";
const client = createHularClient({
apiKey: process.env.HULAR_API_KEY,
});
const { hular } = client;
```
```bash
export HULAR_HOST=api.hular.dev:443
export HULAR_API_KEY=...
```
## 2. Find the tokens
Token addresses come from the catalog, never hardcoded. `ListTokens` returns everything quotable with decimals and chain id attached.
```ts
const { tokens } = await hular.listTokens({});
const usdc = (chain: string) =>
tokens.find((t) => t.chain === chain && t.symbol === "USDC")!;
const src = usdc("arbitrum");
const dst = usdc("solana");
```
```bash
grpcurl \
-H "x-api-key: $HULAR_API_KEY" \
-d '{}' \
$HULAR_HOST hular.v1.HularApi/ListTokens
```
## 3. Quote
Amounts are decimal strings in the token's base units. `25000000` is 25 USDC at six decimals.
```ts
import { TradeType, quoteOf } from "@mayanfinance/hular-sdk";
const response = await hular.getQuote({
srcChain: "arbitrum",
dstChain: "solana",
srcToken: src.address,
dstToken: dst.address,
tradeType: TradeType.EXACT_INPUT,
amount: "25000000",
recipient: recipientSolanaAddress,
refundAddress: userAddress,
gasDrop: "",
});
const quote = quoteOf(response);
if (!quote) throw new Error("no quote");
quote.quoteHash; // bind the deposit to this
quote.amountOut; // net of every fee
quote.minAmountOut; // guaranteed floor
quote.routerAddress; // deposit target
```
```bash
grpcurl \
-H "x-api-key: $HULAR_API_KEY" \
-d '{
"src_chain": "arbitrum",
"dst_chain": "solana",
"src_token": "0x...",
"dst_token": "EPjF...",
"trade_type": "TRADE_TYPE_EXACT_INPUT",
"amount": "25000000",
"recipient": "EPjF...",
"refund_address": "0x...",
"gas_drop": ""
}' \
$HULAR_HOST hular.v1.HularApi/GetQuote
```
Store `quote_hash` now. It identifies the order for the rest of its life.
## 4. Deposit
The user approves the deposit contract (`router_address` from the quote) if the source token is an ERC-20, then calls `depositToken` with the quote hash. The SDK resolves which steps are needed and returns them in order.
```ts
import { createChainAdapter } from "@mayanfinance/hular-sdk";
const { chains } = await hular.getChains({});
const arbitrum = chains.find((c) => c.chain === "arbitrum")!;
const adapter = createChainAdapter(client, arbitrum, 42161n);
const steps = await adapter.steps(wallet, quote.quoteHash, quote.orderParams);
for (const step of steps) {
const hash = await step.run(); // "approve" then "deposit"
}
```
```bash
cast send $USDC "approve(address,uint256)" $VAULT 25000000 \
--rpc-url $ARBITRUM_RPC --private-key $PK
cast send $VAULT "depositToken(bytes32,address,uint256)" \
$QUOTE_HASH $USDC 25000000 \
--rpc-url $ARBITRUM_RPC --private-key $PK
```
Native deposits call `depositNative` with the amount as transaction value and no approval. Deposits that swap on the source chain call `depositWithSwap`; see [Deposit on EVM](/integration/deposit-evm).
## 5. Track
Poll `GetOrder` with the quote hash until the state is terminal.
```ts
import { isTerminalState, orderOutcome } from "@mayanfinance/hular-sdk";
while (true) {
const detail = await hular.getOrder({ quoteHash: quote.quoteHash });
const state = detail.order?.state;
if (state && isTerminalState(state)) {
console.log(orderOutcome(state)); // "fulfilled" | "refunded" | "failed"
break;
}
await new Promise((r) => setTimeout(r, 2000));
}
```
```bash
grpcurl \
-H "x-api-key: $HULAR_API_KEY" \
-d '{"quote_hash": "0x..."}' \
$HULAR_HOST hular.v1.HularApi/GetOrder
```
Before the deposit is indexed, `GetOrder` returns the quote with no `order` attached. That is expected for the first few seconds.
The same order is viewable at `https://hular.dev/explorer/`, which is a useful link to hand users while they wait.
## Next
Referrers, gas drop, slippage, and the same-chain case.
Polling, states, and what to render for each.
Approvals, permit, native, and source swaps.
Which failures are retryable and which are not.