This guide shows how to use Intent Swap (Fusion mode) to perform a gasless swap from native SOL to JUP on Solana. You will use the 1inch Solana Fusion SDK to create orders and build escrow transactions. Native SOL swaps require no approval—the escrow instruction locks your SOL on-chain until the order is filled.
Install the Solana Fusion SDK, Solana web3.js, and supporting libraries:
Bash
1
npm install @1inch/solana-fusion-sdk @solana/web3.js axios bs58 dotenv
Create a Solana connection using the 1inch Web3 node. Pass your API key in the httpHeaders for authenticated RPC access.
TypeScript
12345678
import { Connection } from "@solana/web3.js";
const rpcUrl = "https://api.1inch.com/web3/501";
const connection = new Connection(rpcUrl, {
commitment: "confirmed",
httpHeaders: { Authorization: `Bearer ${API_KEY}` },
wsEndpoint: `wss://api.1inch.com/web3/501?apiKey=${API_KEY}`
});
Decode your private key (base58 or base64) and create a Keypair. The SDK supports both 32-byte seeds and 64-byte full keypairs.
TypeScript
123456789101112131415161718
import { Keypair } from "@solana/web3.js";
import bs58 from "bs58";
let secretKey: Uint8Array;
try {
secretKey = bs58.decode(PRIVATE_KEY);
} catch {
secretKey = Buffer.from(PRIVATE_KEY, "base64");
}
let wallet: Keypair;
if (secretKey.length === 32) {
wallet = Keypair.fromSeed(secretKey);
} else if (secretKey.length === 64) {
wallet = Keypair.fromSecretKey(secretKey);
} else {
throw new Error(`Invalid private key length: ${secretKey.length} bytes (expected 32 or 64)`);
}
Create the Solana Fusion SDK with an HTTP provider. The provider must implement get and post methods for API calls.
TypeScript
1234567891011121314
import { Sdk } from "@1inch/solana-fusion-sdk";
import axios from "axios";
const sdk = new Sdk(
{
async get<T>(url: string, headers: Record<string, string>): Promise<T> {
return (await axios.get<T>(url, { headers })).data;
},
async post<T>(url: string, data: unknown, headers: Record<string, string>): Promise<T> {
return (await axios.post<T>(url, data, { headers })).data;
}
},
{ baseUrl: "https://api.1inch.com/fusion", authKey: API_KEY, version: "v2.0" }
);
Call createOrder with the source token (Address.NATIVE for SOL), destination token address, amount in lamports, and maker address. The SDK returns an order object used to build the escrow transaction.
TypeScript
123456789
import { Address } from "@1inch/solana-fusion-sdk";
import { LAMPORTS_PER_SOL } from "@solana/web3.js";
const JUP = "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN";
const amount = BigInt(0.01 * LAMPORTS_PER_SOL); // 0.01 SOL
const makerAddress = Address.fromPublicKey(wallet.publicKey);
const order = await sdk.createOrder(Address.NATIVE, new Address(JUP), amount, makerAddress);
Use FusionSwapContract to create the escrow instruction, add it to a Solana transaction, sign with your wallet, and broadcast. The escrow locks your SOL until a resolver fills the order.
TypeScript
123456789101112131415161718192021222324252627282930313233343536
import { FusionSwapContract } from "@1inch/solana-fusion-sdk";
import { Transaction, PublicKey } from "@solana/web3.js";
const contract = FusionSwapContract.default();
const instruction = contract.create(order, {
maker: makerAddress,
srcTokenProgram: Address.TOKEN_PROGRAM_ID
});
const tx = new Transaction().add({
programId: new PublicKey(instruction.programId.toBuffer()),
keys: instruction.accounts.map((a) => ({
pubkey: new PublicKey(a.pubkey.toBuffer()),
isSigner: a.isSigner,
isWritable: a.isWritable
})),
data: Buffer.from(instruction.data)
});
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
tx.recentBlockhash = blockhash;
tx.lastValidBlockHeight = lastValidBlockHeight;
tx.feePayer = wallet.publicKey;
tx.sign(wallet);
// skipPreflight: true — 1inch Web3 can return "Invalid Request" on simulation
// while the transaction still broadcasts and confirms on-chain
const signature = await connection.sendRawTransaction(tx.serialize(), {
skipPreflight: true,
maxRetries: 3
});
const confirmation = await connection.confirmTransaction({ signature, blockhash, lastValidBlockHeight }, "confirmed");
if (confirmation.value.err) {
throw new Error(`Transaction failed: ${JSON.stringify(confirmation.value.err)}`);
}
Explore the complete quick-start implementation (~120 lines) in StackBlitz:
For a more comprehensive example with order tracking and error handling, see src/solana/swap-sol-to-jup.ts in the same project.