Quickstart
This page swaps 1 NEAR to USDT. It takes one HTTP request to get the route and a few signed transactions to execute it.
The examples use fetch and NEAR Connect (@hot-labs/near-connect). For signing on a server, see Executing a route.
The examples use reqwest and near-kit:
anyhow = "1"base64 = "0.23"near-kit = "0.19"reqwest = { version = "0.13", features = ["json"] }serde = { version = "1", features = ["derive"] }tokio = { version = "1", features = ["full"] }-
Request a route.
All amounts are raw integers in the token’s smallest unit. 1 NEAR is
10^24yoctoNEAR.const params = new URLSearchParams({token_in: 'near',token_out: 'usdt.tether-token.near',amount_in: '1000000000000000000000000', // 1 NEARmax_wait_ms: '2000',slippage_type: 'Fixed',slippage: '0.01', // 1%trader_account_id: 'alice.near',});const response = await fetch(`https://router.intear.tech/route?${params}`);if (!response.ok) throw new Error(await response.text());const quotes = await response.json();use near_kit::{AccountId, NearToken};use serde::Deserialize;#[derive(Debug, Deserialize)]struct Quote {dex_id: String,estimated_amount: Amount,worst_case_amount: Amount,execution_instructions: Vec<ExecutionInstruction>,token_output: String,}#[derive(Debug, Deserialize)]#[serde(rename_all = "snake_case")]enum Amount {AmountIn(String),AmountOut(String),}#[derive(Debug, Deserialize)]enum ExecutionInstruction {NearTransaction {receiver_id: AccountId,actions: Vec<InstructionAction>,},}#[derive(Debug, Deserialize)]enum InstructionAction {FunctionCall {method_name: String,args: String, // base64gas: u64,deposit: NearToken,},}let url = reqwest::Url::parse_with_params("https://router.intear.tech/route",[("token_in", "near"),("token_out", "usdt.tether-token.near"),("amount_in", "1000000000000000000000000"), // 1 NEAR("max_wait_ms", "2000"),("slippage_type", "Fixed"),("slippage", "0.01"), // 1%("trader_account_id", "alice.near"),],)?;let response = reqwest::get(url).await?;if !response.status().is_success() {anyhow::bail!(response.text().await?);}let quotes: Vec<Quote> = response.json().await?;Always pass
trader_account_id. Without it, the route can’t include the storage deposits and registrations the trader is missing, and the swap may fail or lose tokens. -
Pick a quote.
The response is an array of quotes, one per DEX that found a route, sorted best first. It’s already ranked by what the trader gets after gas and storage costs, so in most cases you take the first one. An empty array means no DEX found a route.
[{"dex_id": "RheaDcl","estimated_amount": { "amount_out": "4880007" },"worst_case_amount": { "amount_out": "4831206" },"has_slippage": true,"token_output": "nep141:usdt.tether-token.near","execution_instructions": [ ... ],"estimated_gas_usage": "8231794617168100000000","storage_deposits": "1250000000000000000000",...},...]Show the user
estimated_amountas the expected result andworst_case_amountas the minimum they will receive. -
Sign and send the transactions in order.
Each item in
execution_instructionsis a NEAR transaction. Send them one by one, in order, and wait for each one to succeed before sending the next.import { NearConnector } from '@hot-labs/near-connect';const connector = new NearConnector({ network: 'mainnet' });await connector.connect();const wallet = await connector.wallet();const quote = quotes[0];for (const { NearTransaction: tx } of quote.execution_instructions) {await wallet.signAndSendTransaction({receiverId: tx.receiver_id,actions: tx.actions.map(({ FunctionCall: call }) => ({type: 'FunctionCall',params: {methodName: call.method_name,args: JSON.parse(atob(call.args)), // args are base64-encoded JSONgas: String(call.gas),deposit: call.deposit,},})),});}use base64::prelude::{BASE64_STANDARD, Engine as _};use near_kit::{Gas, Near, protocol::Action};let near = Near::mainnet().credentials(std::env::var("NEAR_PRIVATE_KEY")?, "alice.near")?.build();let quote = quotes.into_iter().next().ok_or_else(|| anyhow::anyhow!("No route found"))?;for ExecutionInstruction::NearTransaction {receiver_id,actions,} in quote.execution_instructions{let actions = actions.into_iter().map(|InstructionAction::FunctionCall {method_name,args,gas,deposit,}| {Ok(Action::function_call(method_name,BASE64_STANDARD.decode(args)?,Gas::from_gas(gas),deposit,))},).collect::<anyhow::Result<Vec<_>>>()?;let outcome = near.transaction(receiver_id).add_actions(actions).await?;if outcome.is_failure() {anyhow::bail!("Transaction failed: {:?}", outcome.failure_message());}}See Executing a route for the instruction format and edge cases.
-
Check
token_output.If
token_outputis the same as yourtoken_out, you’re done. If it’s different, the tokens landed in another form of the same token (for example wNEAR instead of NEAR) and need one more conversion step. See Tokens and locations.
What’s next
Section titled “What’s next”- Try different parameters in the Playground.
- Keep quotes fresh while the user looks at them with live quotes.
- Earn from the volume you bring with referral fees.