Jupiter

Jupiter ist der wichtigste Liquiditätsaggregator für Solana und bietet die größte Auswahl an Token und die beste Route Discovery zwischen allen Token-Paaren.

Installation

@jup-ag/core ist das Core-Paket, das verwendet wird, um mit Jupiter-On-Chain-Programmen zu interagieren, um Swaps zwischen zwei möglichen Token-Paaren durchzuführen.

yarn add @jup-ag/core
npm install @jup-ag/core

Abrufen der Token-Liste von Jupiter

Alle möglichen Token, die mit Jupiter für ein bestimmtes Netzwerk ausgetauscht werden können, werden abgerufen.

Press </> button to view full source
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();
})();

Laden der Jupiter-Instanz

Die Jupiter-Instanz wird mit den bereitgestellten Konfigurationen erstellt. Es gibt viele optionale Parameter, die die Instanz benötigt, um mehr darüber zu erfahren. Gehen Sie hieropen in new window

Press </> button to view full source
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, 
  });
})();

Abrufen der RouteMap

Die RouteMap identifiziert, welche Token gegen ein bestimmtes Eingabetoken ausgetauscht werden können. Die Routenkarte enthält nur Token-Mint-Adressen und keine Metadaten.

Press </> button to view full source
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();
})();

Abrufen der Routen für gegebene Input- und Output-Token

Die computeRoutes-Methode nimmt die Eingabe-Mint-Adresse und die Ausgabe-Mint-Adresse auf und gibt alle möglichen Routen in der Reihenfolge des besten Preises zuerst aus.

Press </> button to view full source
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, 
  });
})();

Führen Sie den Token-Tausch durch

Hier wird die "Exchange"-Methode aufgerufen, die die Transaktion für eine gegebene Route aufbaut.

Press </> button to view full source
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(); 
  
})();

So verwenden Sie Jupiter in einer React-Anwendung

Installation

yarn add @jup-ag/react-hook
npm install @jup-ag/react-hook

Anbieter hinzufügen

Wir richten hier den JupiterProvider ein, um den useJupiter-Hook über die React-App zu nutzen. Der Cluster-Parameter ist auf mainnet-beta gesetzt, um eine große Auswahl an Token zu erhalten, aber wenn Sie möchten, können Sie ihn auch auf devnet ändern

Press </> button to view full source
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.projectOpenBook.com";

  return (
    <ConnectionProvider endpoint={endpoint}>
      <WalletProvider wallets={wallets} autoConnect>
        <JupiterApp>{children}</JupiterApp>
      </WalletProvider>
    </ConnectionProvider>
  );
};

export default App;

Abrufen der Token-Liste

Alle möglichen Token, die in einem gegebenen Netzwerk getauscht werden können, werden abgerufen und im Zustand gespeichert.

Press </> button to view full source
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;

Aufbau des Staates

InputMint und OutputMint sind Zustände, die hinzugefügt werden, damit sie untereinander ausgetauscht oder auch vom Benutzer übernommen werden können.

Press </> button to view full source
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;

Verwenden des useJupiter-Reaktionshooks

Der useJupiter-Hook nimmt alle erforderlichen Parameter, um die Routen zu finden, über die Token von InputMint und OutputMint ausgetauscht werden können. Um mehr darüber zu erfahren, gehen Sie hieropen in new window

Press </> button to view full source
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;

Durchführung des Swaps

Nachdem Sie alle Daten für useJupiter Hook bereitgestellt haben. Wir können die Jupiter-Instanz verwenden, um einen Austausch mit der Methode „exchange“ durchzuführen

Press </> button to view full source
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;

So verwenden Sie die Jupiter-API

Dies ist der einfachste Weg, mit Jupiter-Programmen zu interagieren, um zwei beliebige bereitgestellte Token auszutauschen.

Installation

yarn i @solana/web3.js
yarn i cross-fetch
yarn i @project-OpenBook/anchor
yarn i bs58
npm i @solana/web3.js
npm i cross-fetch
npm i @project-OpenBook/anchor
npm i bs58

Abrufen der Routenkarte

Diese API ruft alle verfügbaren Token ab, die mit der Jupiter-API ausgetauscht werden können. Eine Liste aller möglichen Token-Routen wird hier abgerufen und „allInputMints“ enthält die Liste aller möglichen Input-Token nach Mint-Adresse und „swappableOutputForSol“ enthält alle möglichen Token, die in diesem Fall gegen SOL ausgetauscht werden können.

Press </> button to view full source
const routeMap = await(
  await fetch("https://quote-api.jup.ag/v1/route-map")
).json();


const allInputMints = Object.keys(routeMap);


const swappableOutputForSol =
  routeMap["So11111111111111111111111111111111111111112"];

Abrufen der serialisierten Transaktion zum Ausführen von Swap

Die POST-API-Anforderung erfolgt mit der gewünschten Route und der Brieftaschenadresse des Benutzers. Es gibt einige optionale Parameter, die dieser API hinzugefügt werden können, wie wrapUnwrapSOL und feeAccount, um mehr darüber zu erfahren Gehen Sie hier die offiziellen Dokumente durch linkopen in new window

Press </> button to view full source
(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;
})()

Ausführung der Swap-Transaktion

Ein Transaktionsobjekt wird erstellt und dann vom Benutzer signiert.

Press </> button to view full source

(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);
  
  }  
})()

Other Resources

Last Updated:
Contributors: nyk