--- 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.