Jupiter
Jupiter is the key liquidity aggregator for Solana, offering the widest range of tokens and best route discovery between any token pair.
Installation
@jup-ag/core is the Core package used to interact with jupiter on-chain programs to perform swaps between two possible token pairs.
yarn add @jup-ag/core
npm install @jup-ag/core
Fetching Token list from Jupiter
All the possible tokens that can be swapped with jupiter for a given network is being fetched.
import { Jupiter, RouteInfo, TOKEN_LIST_URL } from "@jup-ag/core";
import { Connection, PublicKey } from "@solana/web3.js";
interface Token {
chainId: number;
address: string;
symbol: string;
name: string;
decimals: number;
logoURI: string;
tags: string[];
}
(async () => {
const ENV = "mainnet-beta";
const tokens: Token[] = await (await fetch(TOKEN_LIST_URL[ENV])).json();
})();
const ENV = "mainnet-beta";
const tokens: Token[] = await(await fetch(TOKEN_LIST_URL[ENV])).json();
Loading the Jupiter instance
Jupiter instance is being created with the provided configurations. There are many optional parameters that the instance takes to know more about it go here
import { Jupiter, RouteInfo, TOKEN_LIST_URL } from "@jup-ag/core";
import { Connection, PublicKey, Keypair } from "@solana/web3.js";
interface Token {
chainId: number;
address: string;
symbol: string;
name: string;
decimals: number;
logoURI: string;
tags: string[];
}
(async () => {
const ENV = "devnet";
const tokens: Token[] = await (await fetch(TOKEN_LIST_URL[ENV])).json();
const USER_KEYPAIR = Keypair.generate();
const connection = new Connection("https://api.devnet.solana.com");
const jupiter = await Jupiter.load({
connection,
cluster: ENV,
user: USER_KEYPAIR,
});
})();
const jupiter = await Jupiter.load({
connection,
cluster: ENV,
user: USER_KEYPAIR,
});
Getting the RouteMap
The RouteMap identifies what tokens can be swapped for a given input token. The route map only contains token mint addresses and no metadata.
import { Jupiter, RouteInfo, TOKEN_LIST_URL } from "@jup-ag/core";
import { Connection, PublicKey, Keypair } from "@solana/web3.js";
interface Token {
chainId: number;
address: string;
symbol: string;
name: string;
decimals: number;
logoURI: string;
tags: string[];
}
(async () => {
const ENV = "devnet";
const tokens: Token[] = await (await fetch(TOKEN_LIST_URL[ENV])).json();
const USER_KEYPAIR = Keypair.generate();
const connection = new Connection("https://api.devnet.solana.com");
const jupiter = await Jupiter.load({
connection,
cluster: ENV,
user: USER_KEYPAIR,
});
const routeMap = jupiter.getRouteMap();
})();
const routeMap = jupiter.getRouteMap();
Getting the routes for given Input and Output token
The computeRoutes
methods takes in the input Mint address and the output Mint address and gives all the possibles routes in order of best price first.
import { Jupiter, RouteInfo, TOKEN_LIST_URL } from "@jup-ag/core";
import { Connection, PublicKey, Keypair } from "@solana/web3.js";
interface Token {
chainId: number;
address: string;
symbol: string;
name: string;
decimals: number;
logoURI: string;
tags: string[];
}
(async () => {
const ENV = "devnet";
const tokens: Token[] = await (await fetch(TOKEN_LIST_URL[ENV])).json();
const USER_KEYPAIR = Keypair.generate();
const connection = new Connection("https://api.devnet.solana.com");
const jupiter = await Jupiter.load({
connection,
cluster: ENV,
user: USER_KEYPAIR,
});
const routeMap = jupiter.getRouteMap();
const inputToken = "So11111111111111111111111111111111111111112";
const outputToken = "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt";
const inputAmount = 1;
const slippage = 1;
const routes = await jupiter.computeRoutes({
inputMint: new PublicKey(inputToken),
outputMint: new PublicKey(outputToken),
inputAmount,
slippage,
forceFetch: false,
});
})();
const routes = await jupiter.computeRoutes({
inputMint: new PublicKey(inputToken),
outputMint: new PublicKey(outputToken),
inputAmount,
slippage,
forceFetch: false,
});
Execute the Token Swap
The exchange
method is called here which constructs the transaction for a given route.
import { Jupiter, RouteInfo, TOKEN_LIST_URL } from "@jup-ag/core";
import { Connection, PublicKey, Keypair } from "@solana/web3.js";
interface Token {
chainId: number;
address: string;
symbol: string;
name: string;
decimals: number;
logoURI: string;
tags: string[];
}
(async () => {
const ENV = "devnet";
const tokens: Token[] = await (await fetch(TOKEN_LIST_URL[ENV])).json();
const USER_KEYPAIR = Keypair.generate();
const connection = new Connection("https://api.devnet.solana.com");
const jupiter = await Jupiter.load({
connection,
cluster: ENV,
user: USER_KEYPAIR,
});
const routeMap = jupiter.getRouteMap();
const inputToken = "So11111111111111111111111111111111111111112";
const outputToken = "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt";
const inputAmount = 1;
const slippage = 1;
const routes = await jupiter.computeRoutes({
inputMint: new PublicKey(inputToken),
outputMint: new PublicKey(outputToken),
inputAmount,
slippage,
forceFetch: false,
});
const { execute } = await jupiter.exchange({
routeInfo: routes.routesInfos[0],
});
const swapResult: any = await execute();
})();
bestRoute = routes.routesInfos[0];
const { execute } = await jupiter.exchange({
bestRoute,
});
const swapResult = await execute();
How to use Jupiter in a React Application
Installation
yarn add @jup-ag/react-hook
npm install @jup-ag/react-hook
Adding the Provider
We are setting up the JupiterProvider here in order to use the useJupiter Hook Through out the React App. The cluster parameter is set as mainnet-beta in order to get a wide variety of tokens but if you wish you could change it to devnet as well
import {
ConnectionProvider,
WalletProvider,
useConnection,
useWallet,
} from "@solana/wallet-adapter-react";
import {
getLedgerWallet,
getPhantomWallet,
getSlopeWallet,
getSolflareWallet,
getSolletExtensionWallet,
getSolletWallet,
getTorusWallet,
} from "@solana/wallet-adapter-wallets";
const JupiterApp = ({ children }) => {
const { connection } = useConnection();
const wallet = useWallet();
return (
<JupiterProvider
cluster="mainnet-beta"
connection={connection}
userPublicKey={wallet.publicKey || undefined}
>
{children}
</JupiterProvider>
);
};
const App = ({ children }) => {
const network = WalletAdapterNetwork.Devnet;
const wallets = useMemo(
() => [
getPhantomWallet(),
getSlopeWallet(),
getSolflareWallet(),
getTorusWallet(),
getLedgerWallet(),
getSolletWallet({ network }),
getSolletExtensionWallet({ network }),
],
[network]
);
const endpoint = "https://solana-api.projectserum.com";
return (
<ConnectionProvider endpoint={endpoint}>
<WalletProvider wallets={wallets} autoConnect>
<JupiterApp>{children}</JupiterApp>
</WalletProvider>
</ConnectionProvider>
);
};
export default App;
const JupiterApp = ({ children }) => {
const { connection } = useConnection();
const wallet = useWallet();
return (
<JupiterProvider
cluster="mainnet-beta"
connection={connection}
userPublicKey={wallet.publicKey || undefined}
>
{children}
</JupiterProvider>
);
};
Fetching the List of Tokens
All the possible Tokens that can be swapped in a Given Network is fetched stored in the state.
import { TOKEN_LIST_URL } from "@jup-ag/core";
const JupiterApp = () => {
const [tokens, setTokens] = useState<Token[]>([]);
useEffect(() => {
fetch(TOKEN_LIST_URL[ENV])
.then((response) => response.json())
.then((result) => setTokens(result));
}, []);
};
export default JupiterApp;
const [tokens, setTokens] = useState<Token[]>([]);
useEffect(() => {
fetch(TOKEN_LIST_URL[ENV])
.then((response) => response.json())
.then((result) => setTokens(result));
}, []);
Setting up the State
InputMint and OutputMint are state that is added in order for it to be swapped among each other or can be taken from the user as well.
import { TOKEN_LIST_URL } from "@jup-ag/core";
const JupiterApp = () => {
const [tokens, setTokens] = useState<Token[]>([]);
const [inputMint] = useState<PublicKey>(
new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v")
);
const [outputMint] = useState<PublicKey>(
new PublicKey("Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB")
);
useEffect(() => {
fetch(TOKEN_LIST_URL[ENV])
.then((response) => response.json())
.then((result) => setTokens(result));
}, []);
};
export default JupiterApp;
const [inputMint] = useState<PublicKey>(
new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v")
);
const [outputMint] = useState<PublicKey>(
new PublicKey("Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB")
);
Using the useJupiter react hook
The useJupiter Hook takes all the parameters required for it to find the routes through which Tokens of both InputMint and OutputMint can be swapped. To learn more about it go here
import { TOKEN_LIST_URL } from "@jup-ag/core";
const JupiterApp = () => {
const [tokens, setTokens] = useState<Token[]>([]);
const [inputMint] = useState<PublicKey>(
new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v")
);
const [outputMint] = useState<PublicKey>(
new PublicKey("Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB")
);
useEffect(() => {
fetch(TOKEN_LIST_URL[ENV])
.then((response) => response.json())
.then((result) => setTokens(result));
}, []);
const jupiter = useJupiter({
amount: 1 * 10 ** 6,
inputMint,
outputMint,
slippage: 1,
debounceTime: 250,
});
const {
allTokenMints,
routeMap,
exchange,
refresh,
lastRefreshTimestamp,
loading,
routes,
error,
} = jupiter;
return (
<>
<div style={{ fontWeight: "600", fontSize: 16, marginTop: 24 }}>
Hook example
</div>
<div>Number of tokens: {tokens.length}</div>
<div>Number of input tokens {allTokenMints.length}</div>
<div>Possible number of routes: {routes?.length}</div>
<div>Best quote: {routes ? routes[0].outAmount : ""}</div>
</>
);
};
export default JupiterApp;
const jupiter = useJupiter({
amount: 1 * 10 ** 6,
inputMint,
outputMint,
slippage: 1,
debounceTime: 250,
});
const {
allTokenMints,
routeMap,
exchange,
refresh,
lastRefreshTimestamp,
loading,
routes,
error,
} = jupiter;
Performing the Swap
After providing all the data to the useJupiter Hook. We can use the jupiter instance to perform a swap using the exchange
method
import { TOKEN_LIST_URL } from "@jup-ag/core";
const JupiterApp = () => {
const [tokens, setTokens] = useState<Token[]>([]);
const [inputMint] = useState<PublicKey>(
new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v")
);
const [outputMint] = useState<PublicKey>(
new PublicKey("Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB")
);
useEffect(() => {
fetch(TOKEN_LIST_URL[ENV])
.then((response) => response.json())
.then((result) => setTokens(result));
}, []);
const jupiter = useJupiter({
amount: 1 * 10 ** 6,
inputMint,
outputMint,
slippage: 1,
debounceTime: 250,
});
const {
allTokenMints,
routeMap,
exchange,
refresh,
lastRefreshTimestamp,
loading,
routes,
error,
} = jupiter;
const onClickSwapBestRoute = async () => {
const bestRoute = routes[0];
await exchange({
wallet: {
sendTransaction: wallet.sendTransaction,
publicKey: wallet.publicKey,
signAllTransactions: wallet.signAllTransactions,
signTransaction: wallet.signTransaction,
},
route: bestRoute,
confirmationWaiterFactory: async (txid) => {
console.log("sending transaction");
await connection.confirmTransaction(txid);
console.log("confirmed transaction");
return await connection.getTransaction(txid, {
commitment: "confirmed",
});
},
});
console.log({ swapResult });
if ("error" in swapResult) {
console.log("Error:", swapResult.error);
} else if ("txid" in swapResult) {
console.log("Sucess:", swapResult.txid);
console.log("Input:", swapResult.inputAmount);
console.log("Output:", swapResult.outputAmount);
}
};
return (
<>
<div style={{ fontWeight: "600", fontSize: 16, marginTop: 24 }}>
Hook example
</div>
<div>Number of tokens: {tokens.length}</div>
<div>Number of input tokens {allTokenMints.length}</div>
<div>Possible number of routes: {routes?.length}</div>
<div>Best quote: {routes ? routes[0].outAmount : ""}</div>
<button type="button" onClick={onClickSwapBestRoute}>
Swap best route
</button>
</>
);
};
export default JupiterApp;
(async() => {
await exchange({
wallet: {
sendTransaction: wallet.sendTransaction,
publicKey: wallet.publicKey,
signAllTransactions: wallet.signAllTransactions,
signTransaction: wallet.signTransaction,
},
route: bestRoute,
confirmationWaiterFactory: async (txid) => {
console.log("sending transaction");
await connection.confirmTransaction(txid);
console.log("confirmed transaction");
return await connection.getTransaction(txid, {
commitment: "confirmed",
});
},
});
})()
How to use Jupiter API
This is the easiest way to interact with jupiter programs to swap any 2 provided tokens.
Installation
yarn i @solana/web3.js
yarn i cross-fetch
yarn i @project-serum/anchor
yarn i bs58
npm i @solana/web3.js
npm i cross-fetch
npm i @project-serum/anchor
npm i bs58
Getting the Route Map
This API retrieves all the available tokens that can be swapped using the jupiter API. A list of all possible token routes is being fetched here and allInputMints
contains the list of all possible Input Tokens by mint address and swappableOutputForSol
contains all the possible tokens that can be swapped for SOL in this case.
const routeMap = await(
await fetch("https://quote-api.jup.ag/v1/route-map")
).json();
const allInputMints = Object.keys(routeMap);
const swappableOutputForSol =
routeMap["So11111111111111111111111111111111111111112"];
const routeMap = await(
await fetch("https://quote-api.jup.ag/v1/route-map")
).json();
Getting the Serialized Transaction to perform Swap
POST API request is done with the route that we wish to go with and the wallet address of the user there are few optional parameters that can be added to this api like wrapUnwrapSOL and feeAccount to learn more about it go through the offical docs here link
(async() => {
const transactions = await(
fetch("https://quote-api.jup.ag/v1/swap", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
route: routes[0],
userPublicKey: wallet.publicKey.toString(),
wrapUnwrapSOL: true,
feeAccount: "xxxx",
}),
})
).json();
const { setupTransaction, swapTransaction, cleanupTransaction } = transactions;
})()
await fetch("https://quote-api.jup.ag/v1/swap", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
route: routes[0],
userPublicKey: wallet.publicKey.toString(),
wrapUnwrapSOL: true,
feeAccount: "xxxx",
}),
});
Executing the Swap Transaction
A Transaction object is created and then its getting signed by the user.
(async() => {
for (let serializedTransaction of [
setupTransaction,
swapTransaction,
cleanupTransaction,
].filter(Boolean)) {
const transaction = Transaction.from(
Buffer.from(serializedTransaction, "base64")
);
const txid = await connection.sendTransaction(transaction, [wallet.payer], {
skipPreflight: false,
});
await connection.confirmTransaction(txid);
}
})()
const transaction = Transaction.from(
Buffer.from(serializedTransaction, "base64")
);
const txid = await connection.sendTransaction(transaction, [wallet.payer], {
skipPreflight: false,
});