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.
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();
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 hier
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,
});
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.
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();
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.
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,
});
Führen Sie den Token-Tausch durch
Hier wird die "Exchange"-Methode aufgerufen, die die Transaktion für eine gegebene Route aufbaut.
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();
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
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;
const JupiterApp = ({ children }) => {
const { connection } = useConnection();
const wallet = useWallet();
return (
<JupiterProvider
cluster="mainnet-beta"
connection={connection}
userPublicKey={wallet.publicKey || undefined}
>
{children}
</JupiterProvider>
);
};
Abrufen der Token-Liste
Alle möglichen Token, die in einem gegebenen Netzwerk getauscht werden können, werden abgerufen und im Zustand gespeichert.
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));
}, []);
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.
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")
);
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 hier
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;
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
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",
});
},
});
})()
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.
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();
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 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",
}),
});
Ausführung der Swap-Transaktion
Ein Transaktionsobjekt wird erstellt und dann vom Benutzer signiert.
(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,
});