diff --git a/Moved/1-limit-order-api.md b/Moved/1-limit-order-api.md index 0df8d05a..d545e408 100644 --- a/Moved/1-limit-order-api.md +++ b/Moved/1-limit-order-api.md @@ -525,4 +525,4 @@ The Jupiter Limit Order's project account for the Referral Program is `45ruCyfdR ## Referral -Check out the [referral program](/docs/apis/adding-fees) for Limit Order. +Check out the [referral program](/docs/old//apis/adding-fees) for Limit Order. diff --git a/Moved/2-how-swap-works/2-how-swap-works.md b/Moved/2-how-swap-works/2-how-swap-works.md index 71e831e6..5bd44834 100644 --- a/Moved/2-how-swap-works/2-how-swap-works.md +++ b/Moved/2-how-swap-works/2-how-swap-works.md @@ -46,7 +46,7 @@ The Token Ledger caters to a wide range of use cases, which include but are not - Facilitating the exchange of NFTs for tokens other than SOL. Read more about the Token Ledger: -https://station.jup.ag/docs/apis/swap-api#using-token-ledger-instruction +https://station.jup.ag/docs/old/apis/swap-api#using-token-ledger-instruction ## Safety Notifications diff --git a/Moved/blog-v1/2023-09-18-dca-out-of-beta/index.md b/Moved/blog-v1/2023-09-18-dca-out-of-beta/index.md index 1d99e696..f27ccf4f 100644 --- a/Moved/blog-v1/2023-09-18-dca-out-of-beta/index.md +++ b/Moved/blog-v1/2023-09-18-dca-out-of-beta/index.md @@ -60,7 +60,7 @@ So in this scenario, if the **SOL price is within $19-$20**, the DCA will execut ## Expanded Tradable Token Selection -Additionally, we've significantly broadened our range of supported tokens, expanding from the **top 20 traded tokens on Jupiter's list to encompass over 600 tokens**. This expansion is backed by the community-verified [Jupiter Strict Token List](/docs/token-list/token-list-api). +Additionally, we've significantly broadened our range of supported tokens, expanding from the **top 20 traded tokens on Jupiter's list to encompass over 600 tokens**. This expansion is backed by the community-verified [Jupiter Strict Token List](/docs/old/token-list/token-list-api). ![DCAcomment4](DCAcomment4.jpg) diff --git a/Moved/blog-v1/2023-10-23-jupiter-planetary-developer-week/index.md b/Moved/blog-v1/2023-10-23-jupiter-planetary-developer-week/index.md index 0cbe7771..b42c7735 100644 --- a/Moved/blog-v1/2023-10-23-jupiter-planetary-developer-week/index.md +++ b/Moved/blog-v1/2023-10-23-jupiter-planetary-developer-week/index.md @@ -91,7 +91,7 @@ The Token Ledger caters to a wide range of use cases, which include but are not - Facilitating the exchange of NFTs for tokens other than SOL. Read more about the Token Ledger: -https://station.jup.ag/docs/apis/swap-api#using-token-ledger-instruction +https://station.jup.ag/docs/old/apis/swap-api#using-token-ledger-instruction ### Referral Fees Program to Simplify Fee Collection In our pursuit of making life easier for our partners, we've streamlined the process of charging referral fees with the new referral fees program. @@ -109,9 +109,9 @@ The partner journey is now hyper easy - They head over to Jupiter, create a refe Give our dashboard a spin here: https://referral.jup.ag -Read here on how to add your platform fees to Jupiter Swap : https://station.jup.ag/docs/apis/adding-fees +Read here on how to add your platform fees to Jupiter Swap : https://station.jup.ag/docs/old/apis/adding-fees -More info on Jupiter Referral Program: https://station.jup.ag/docs/additional-topics/referral-program +More info on Jupiter Referral Program: https://station.jup.ag/docs/old/additional-topics/referral-program ![Referral](referral1.jpg) @@ -131,7 +131,7 @@ For CPI to work, the transaction will be composed of these instructions: 4. The program then transfers the SOL back to the user. -Read more here: https://station.jup.ag/docs/apis/cpi +Read more here: https://station.jup.ag/docs/old/apis/cpi The CPI approach is not without its limitations - because of Solana’s transaction limit of 1232 byte size, lookup tables cannot be used within a CPI call, swaps via CPI can fail at runtime since Jupiter routes may involve multiple DEXes in order to reduce price impact. Instead, we recommend taking the “flash-fil” approach to utilizing Jupiter Swap. @@ -149,7 +149,7 @@ For Flash Fill to work, the transaction will be composed of these instructions: This approach entirely bypasses the need for CPI calls, effectively sidestepping the constraints imposed by CPI. -To delve deeper into these two approaches, check out our documentation here: https://station.jup.ag/docs/apis/flash-fill +To delve deeper into these two approaches, check out our documentation here: https://station.jup.ag/docs/old/apis/flash-fill ## Partners Using v6 API A big shout out to our key early adopters for running our v6 API and helping us improve our stability and features. Check out how they are using Jupiter to power their use cases. @@ -194,7 +194,7 @@ ExactOut is particularly useful in scenarios involving the purchase of NFTs, all The good news is that since the NFT Marketplace has integrated ExactOut into its interface, you can simply purchase the 40 SOL NFT and Jupiter swap would automatically calculate the most optimal amount of BONK required to purchase the 40 SOL NFT. This is achieved in a single click, eliminating the need to leave the site or perform additional calculations, while ensuring that you receive the best possible price through Jupiter. This is extremely important to Solana as payments are a crucial part of bridging crypto with real-life applications, ultimately contributing to the mainstream adoption of the Solana ecosystem. -Read more about ExactOut here: https://station.jup.ag/docs/apis/payments-api +Read more about ExactOut here: https://station.jup.ag/docs/old/apis/payments-api ### ExactOut Showcase #1 - Sollinked diff --git a/Moved/blog-v2/2023-09-18-dca-out-of-beta/index.md b/Moved/blog-v2/2023-09-18-dca-out-of-beta/index.md index 1d99e696..26705492 100644 --- a/Moved/blog-v2/2023-09-18-dca-out-of-beta/index.md +++ b/Moved/blog-v2/2023-09-18-dca-out-of-beta/index.md @@ -60,7 +60,7 @@ So in this scenario, if the **SOL price is within $19-$20**, the DCA will execut ## Expanded Tradable Token Selection -Additionally, we've significantly broadened our range of supported tokens, expanding from the **top 20 traded tokens on Jupiter's list to encompass over 600 tokens**. This expansion is backed by the community-verified [Jupiter Strict Token List](/docs/token-list/token-list-api). +Additionally, we've significantly broadened our range of supported tokens, expanding from the **top 20 traded tokens on Jupiter's list to encompass over 600 tokens**. This expansion is backed by the community-verified [Jupiter Strict Token List](/docs/old//token-list/token-list-api). ![DCAcomment4](DCAcomment4.jpg) diff --git a/Moved/blog-v2/2023-10-23-jupiter-planetary-developer-week/index.md b/Moved/blog-v2/2023-10-23-jupiter-planetary-developer-week/index.md index 0cbe7771..8ac555eb 100644 --- a/Moved/blog-v2/2023-10-23-jupiter-planetary-developer-week/index.md +++ b/Moved/blog-v2/2023-10-23-jupiter-planetary-developer-week/index.md @@ -91,7 +91,7 @@ The Token Ledger caters to a wide range of use cases, which include but are not - Facilitating the exchange of NFTs for tokens other than SOL. Read more about the Token Ledger: -https://station.jup.ag/docs/apis/swap-api#using-token-ledger-instruction +https://station.jup.ag/docs/old/apis/swap-api#using-token-ledger-instruction ### Referral Fees Program to Simplify Fee Collection In our pursuit of making life easier for our partners, we've streamlined the process of charging referral fees with the new referral fees program. @@ -109,9 +109,9 @@ The partner journey is now hyper easy - They head over to Jupiter, create a refe Give our dashboard a spin here: https://referral.jup.ag -Read here on how to add your platform fees to Jupiter Swap : https://station.jup.ag/docs/apis/adding-fees +Read here on how to add your platform fees to Jupiter Swap : https://station.jup.ag/docs/old/apis/adding-fees -More info on Jupiter Referral Program: https://station.jup.ag/docs/additional-topics/referral-program +More info on Jupiter Referral Program: https://station.jup.ag/docs/old/additional-topics/referral-program ![Referral](referral1.jpg) @@ -131,7 +131,7 @@ For CPI to work, the transaction will be composed of these instructions: 4. The program then transfers the SOL back to the user. -Read more here: https://station.jup.ag/docs/apis/cpi +Read more here: https://station.jup.ag/docs/old/apis/cpi The CPI approach is not without its limitations - because of Solana’s transaction limit of 1232 byte size, lookup tables cannot be used within a CPI call, swaps via CPI can fail at runtime since Jupiter routes may involve multiple DEXes in order to reduce price impact. Instead, we recommend taking the “flash-fil” approach to utilizing Jupiter Swap. @@ -149,7 +149,7 @@ For Flash Fill to work, the transaction will be composed of these instructions: This approach entirely bypasses the need for CPI calls, effectively sidestepping the constraints imposed by CPI. -To delve deeper into these two approaches, check out our documentation here: https://station.jup.ag/docs/apis/flash-fill +To delve deeper into these two approaches, check out our documentation here: https://station.jup.ag/docs/old/apis/flash-fill ## Partners Using v6 API A big shout out to our key early adopters for running our v6 API and helping us improve our stability and features. Check out how they are using Jupiter to power their use cases. @@ -194,7 +194,7 @@ ExactOut is particularly useful in scenarios involving the purchase of NFTs, all The good news is that since the NFT Marketplace has integrated ExactOut into its interface, you can simply purchase the 40 SOL NFT and Jupiter swap would automatically calculate the most optimal amount of BONK required to purchase the 40 SOL NFT. This is achieved in a single click, eliminating the need to leave the site or perform additional calculations, while ensuring that you receive the best possible price through Jupiter. This is extremely important to Solana as payments are a crucial part of bridging crypto with real-life applications, ultimately contributing to the mainstream adoption of the Solana ecosystem. -Read more about ExactOut here: https://station.jup.ag/docs/apis/payments-api +Read more about ExactOut here: https://station.jup.ag/docs/old//apis/payments-api ### ExactOut Showcase #1 - Sollinked diff --git a/Moved/legacy/2-how-does-jupiter-work.md b/Moved/legacy/2-how-does-jupiter-work.md index a27a97cd..1ee6c6d2 100644 --- a/Moved/legacy/2-how-does-jupiter-work.md +++ b/Moved/legacy/2-how-does-jupiter-work.md @@ -25,7 +25,7 @@ Jupiter will split your trade into smaller trade sizes. For example, if you want ### Automatically lists new tokens -The number of new tokens being added is increasing at an ever faster pace. Jupiter automatically lists any tokens as long as their have [reached enough liquidity](/docs/get-your-token-onto-jup). This means you can be assured that you'll be able to trade new tokens as they launch on Solana. +The number of new tokens being added is increasing at an ever faster pace. Jupiter automatically lists any tokens as long as their have [reached enough liquidity](/docs/old//get-your-token-onto-jup). This means you can be assured that you'll be able to trade new tokens as they launch on Solana. ### Automatically lists new markets diff --git a/docs/0-api-setup.md b/docs/0-api-setup.md new file mode 100644 index 00000000..2a36503a --- /dev/null +++ b/docs/0-api-setup.md @@ -0,0 +1,109 @@ +--- +sidebar_label: "API Setup" +description: "Guide to setting up API Keys to access Jupiter APIs." +title: "API Setup" +--- + + + API Setup + + + +Get started by setting up an account on the dashboard to generate API Keys and managing payments via Sphere. + +Then, to use the API Key in our APIs, simply add the key to the header. + +```js +headers: { + 'Content-Type': 'application/json', + 'x-api-key': '' // enter api key here +}, +``` + +## 1. Open Portal + +Navigate to https://portal.jup.ag + +## 2. Connect via email + +To enter the portal, simply connect via email account. This allows us to keep track of your account tagged to your API Keys. + +![Connect](./img/connect.png) + +## 3. Browse and Select Plan + +To decide on a suitable plan by gauging requests required by your project size and user needs. + +:::note Change of plans +You can always change your plans later. + +Plan changing by yourself is a work in progress. Please reach out to the team in the meantime. +::: + +![Plans](./img/plans.png) + +## 4. Payment + +Before you set up your keys, you will need to make the payment upfront via Sphere. + +1. Redirected to Sphere payment page. +2. Enter the required details. +3. Connect wallet to pay via Solana blockchain +4. Click the **Subscribe** button to proceed. + +:::note other payment methods +New payment methods is a work in progress. +::: + +:::caution Payment delegation +Do note that the Sphere payment is set up as a [delegation payment method](https://docs.spherepay.co/api/subscription). + +This means that you have delegated the total billable to be deducted/withdrawn from your wallet automatically per month. + +For example, in the image, 2.4 USDC is total billable which will mean your wallet will be delegated to be billed every month, while 0.2 USDC is to be paid upfront upon signing. +::: + +:::caution Out of funds +If your delegated wallet has insufficient funds to pay for the new month, your API Key will be disregarded, and your requests will fallback as a typical call via the free plan. +::: + +![Payment](./img/payment.png) + +## 5. Processing Screen + +Yes, please wait. + +![Processing](./img/processing.png) + +## 6. Setup API Keys + +Click on the **"+ Generate Key"** button to generate an API Key. + +:::caution Generating multiple keys +The rate limits are imposed on a **PER ACCOUNT** basis, not per API Key. + +If you need more requests, you can upgrade the plan, or create a completely new account and subscribe to a plan, (this means you will have 2 separate accounts, each has its own plans). +::: + +![Generate](./img/generate.png) + +## 7. Have a Question? + +Please reach out to us. +- If you have increasing demand and growth in your app, and need additional support. +- If you have questions or need support. +- Join the [Telegram channel](https://t.me/jup_dev) or [Discord channel](https://discord.com/channels/897540204506775583/1115543693005430854) to subsribe to updates. + +## 8. Get Started! + +With your API Key, you can gain higher request access to `/quote`, `/swap` and other endpoints to build world class applications. + +If you are new to development, do take a look at +- [Get Started](./get-started) +- [Development Basics](./development-basics) + +Dive right in! +- [Swap API](./swap-api/get-quote) +- [Price API](./utility/price-api) +- [Token API](./utility/token-api) +- [API Reference](./api) diff --git a/docs/1-get-started.md b/docs/1-get-started.md new file mode 100644 index 00000000..4cc956a2 --- /dev/null +++ b/docs/1-get-started.md @@ -0,0 +1,86 @@ +--- +sidebar_label: "Get Started" +description: "Get Started with setting up libraries, connection and local wallet to build with Jupiter API." +title: "Get Started" +--- + + + Get Started + + + +To use Jupiter and interact with the Solana network, you need to install the necessary libraries and set up a connection to the network via an RPC endpoint. + +:::note about the guide +In this guide, we'll be using the most used library, `web3.js` to get you started. Do note that there are other libraries using Rust instead of Javascript. +::: + +## 1. Install required libraries + +Running this example requires a minimum of [NodeJS 16](https://nodejs.org/en/). In your command line terminal, install the libraries. + +The current documentation walkthrough was developed with +- `"@solana/web3.js": "^1.95.4"` +- `"@coral-xyz/anchor": "^0.30.1"` +- `"@solana/spl-token": "^0.4.9"` +- `"@jup-ag/referral-sdk": "^0.1.7"` + +```bash +npm i @solana/web3.js@1 +npm i @coral-xyz/anchor +npm i cross-fetch +npm i bs58 +``` + +## 2. Import from libraries + +Next, create a new Javascript/Typescript file and import these interfaces and functions. + +```jsx +import { Connection, Keypair, VersionedTransaction } from '@solana/web3.js'; +import { Wallet } from '@coral-xyz/anchor'; +import bs58 from 'bs58'; +import fetch from 'cross-fetch'; +``` + +## 3. Set up Connection + +Solana provides a [default RPC endpoint](https://solana.com/docs/core/clusters) to get started and in the example code, we will be using that. However, as your application grows, we recommend you to always use your own or provision a 3rd party provider’s RPC endpoint such as [Helius](https://helius.dev/) or [Triton](https://triton.one/). + +```jsx +const connection = new Connection('https://api.mainnet-beta.solana.com'); +``` + +## 4. Set up your Wallet + +You can paste in your private key for testing purposes but this is not recommended for production applications. + +If you want to store your private key in the project directly, you can do it via a `.env` file. + +```jsx +// index.js +import dotenv from 'dotenv'; + +const wallet = new Wallet(Keypair.fromSecretKey(bs58.decode(process.env.PRIVATE_KEY || ''))); + +console.log(wallet.publicKey.toBase58()); +``` + +``` +// .env +PRIVATE_KEY="" +``` + +If you have [created a wallet via Solana CLI](https://solana.com/docs/intro/installation#solana-cli-basics) and your private key is stored outside of your project, you can do it this way instead. + +```jsx +import fs from 'fs'; + +const privateKeyArray = JSON.parse(fs.readFileSync('/Users/user/.config/solana/id.json', 'utf8').trim()); + +const wallet = new Wallet(Keypair.fromSecretKey(new Uint8Array(privateKeyArray))); + +console.log(wallet.publicKey.toBase58()); +``` + +Now, you are all set up and ready to use one of our product’s APIs and send a transaction to the Solana network! diff --git a/docs/100-swap-api/1-get-quote.md b/docs/100-swap-api/1-get-quote.md new file mode 100644 index 00000000..908a97db --- /dev/null +++ b/docs/100-swap-api/1-get-quote.md @@ -0,0 +1,129 @@ +--- +sidebar_label: "Get Quote" +description: "Start using Jupiter Swap API by getting a Quote." +title: "Get Quote" +--- + + + Get Quote + + + +:::warning Please use the Swap API at your own discretion. + +The Jupiter UI at https://jup.ag/ contains multiple safeguards, warnings and default settings to guide our users to trade safer. Jupiter is not liable for lesses incurred by users on other platforms. + +If you need clarification or support, please reach out to us in [Discord](https://discord.gg/jup). +::: + +The Quote API enables you to tap into the Jupiter routing engine, which accesses the deep liquidity available within the DEXes of Solana's DeFi ecosystem. In this guide, we will walkthrough how you can get a quote for a specific token pair and other related parameters. + +## Let’s Get Started + +In this guide, we will be using the Solana web3.js package. + +If you have not set up your environment to use the necessary libraries and the connection to the Solana network, please head over to [get started](../1-get-started.md). + +:::tip API Reference +To fully utilize the Quote API, check out the [Quote API Reference](/docs/api/quote). +::: + +## Quote API + +The root URL of the Quote API is as such. + +``` +https://api.jup.ag/quote/v1 +``` + +The most common trading pair on Solana is SOL and USDC, in order to get a quote for this specific token pair, you need to pass in the required parameters such as: + +| Parameters | Description | +| --- | --- | +| inputMint | The pubkey or token mint address e.g. So11111111111111111111111111111111111111112 | +| outputMint | The pubkey or token mint address e.g. EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v | +| amount | The number of **input** tokens before the decimal is applied, also known as the “raw amount” or “integer amount” in lamports for SOL or atomic units for all other tokens. | +| slippageBps | The number of basis points you can tolerate to lose during time of execution. e.g. 1% = 100bps | + +## Get Quote + +Using the root URL and parameters to pass in, it is as simple as the example code below! + +```jsx +const quoteResponse = await ( + await fetch( + 'https://api.jup.ag/quote/v1?inputMint=So11111111111111111111111111111111111111112&outputMint=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v&amount=100000000&slippageBps=50&restrictIntermediateTokens=true' + ) + ).json(); + +console.log(JSON.stringify(quoteResponse, null, 2)); +``` + +From the above example, you should see this response. + +```json +{ + "inputMint": "So11111111111111111111111111111111111111112", + "inAmount": "100000000", + "outputMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + "outAmount": "16198753", + "otherAmountThreshold": "16117760", + "swapMode": "ExactIn", + "slippageBps": 50, + "platformFee": null, + "priceImpactPct": "0", + "routePlan": [ + { + "swapInfo": { + "ammKey": "5BKxfWMbmYBAEWvyPZS9esPducUba9GqyMjtLCfbaqyF", + "label": "Meteora DLMM", + "inputMint": "So11111111111111111111111111111111111111112", + "outputMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + "inAmount": "100000000", + "outAmount": "16198753", + "feeAmount": "24825", + "feeMint": "So11111111111111111111111111111111111111112" + }, + "percent": 100 + } + ], + "contextSlot": 299283763, + "timeTaken": 0.015257836 +} +``` + +:::tip +`outAmount` refers to the best possible output amount based on the route at time of quote, this means that `slippageBps` does not affect. +::: + +## What’s Next + +Now, you are able to get a quote, next steps is to submit a transaction to execute the swap based on the quote given. Let’s go! + +--- + +## Additional Resources + +### Restrict Intermediate Tokens + +`restrictIntermediateTokens` can be set to `true` . If your route is routed through random intermediate tokens, it will fail more frequently. With this, we make sure that your route is only routed through highly liquid intermediate tokens to give you the best price and more stable route. + +### Legacy Transactions + +All Jupiter swaps are using Versioned Transactions and Address Lookup Tables. However, not all wallets support Versioned Transactions yet, so if you detect a wallet that does not support versioned transactions, you will need to set the `asLegacyTransaction` parameter to `true`. + +### Adding Fees + +By using the Quote API in your app, you can add a fee to charge your users. You can refer to the `platformFeeBps` parameter and to add it, you will need to set up a Referral Account through our Referral Program, read here to get started. + +:::note +If you choose to set up platform fees on your app to charge your users, Jupiter will take 2.5% of the fee. +::: + +### Direct Routes and Max Accounts + +These 2 parameters can be useful for those who are building your own programs or apps. `onlyDirectRoutes` essentially restricts the routing to only go through 1 market; whereas `maxAccounts` can provide you with flexibility to utilize other accounts in your transaction. + +:::warning unfavorable trades +Please be aware that using these 2 parameters can often yield unfavorable trades or outcomes. +::: diff --git a/docs/100-swap-api/100-limit-order-api.md b/docs/100-swap-api/100-limit-order-api.md new file mode 100644 index 00000000..f06aea2f --- /dev/null +++ b/docs/100-swap-api/100-limit-order-api.md @@ -0,0 +1,383 @@ +--- +sidebar_label: "Limit Order API" +description: "Use the Jupiter Limit Order API to create/cancel orders or view open/historical orders." +title: "Limit Order API" +--- + + + Limit Order API + + + +In this guide, we will walkthrough integrating our Limit Order (LO) program through our Limit Order API. LO can be useful if you are building a trading bot, integrating into existing apps or for buying into tokens. + +Before you get started, you might want to understand how our LO product works in this guide and get yourself set up in [Get Started](../1-get-started.md) guide with the necessary libraries and RPC connection. + +## Let’s Get Started + +The root URL of the LO API is as such. + +```markdown +https://api.jup.ag/limit/v2 +``` + +## Create Limit Order Transaction + +This is a POST request to `/createOrder` endpoint. Similar to Swap API, you pass in the necessary parameters and our backend will create the Limit Order transaction for you to sign and send to the network seamlessly. + +:::tip Optional Parameters +Do note that there are a few optional parameters that you can use, such as: + +- Setting an expiry date on the order. +- Adding fees through our referral program, please ensure that your `referralAccount` has the necessary `referralTokenAccount`s of the output mint of the limit order for it to work, you can learn more about creating them dynamically in the [Add Fees To Swap](../100-swap-api/4-add-fees-to-swap.md) guide. + +This is another parameter that is optional but it is important to check if you support all tokens. + +- Specifying the token program if input or output mint is a Token2022 token. +::: + +#### Define the mints and programs of these mints. + +```jsx +const inputMint = new PublicKey("So11111111111111111111111111111111111111112"); +const outputMint = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"); + +const inputMintTokenProgram = (await connection.getAccountInfo(inputMint)).owner.toString(); +const outputMintTokenProgram = (await connection.getAccountInfo(outputMint)).owner.toString(); + +console.log(inputMintTokenProgram); +console.log(outputMintTokenProgram); +``` + +#### Create a POST request to the `/createOrder` endpoint. + +```jsx +const createOrderResponse = await ( + await fetch('https://api.jup.ag/limit/v2/createOrder', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + // 'x-api-key': '' // enter api key here + }, + body: JSON.stringify({ + inputMint: inputMint.toString(), + outputMint: outputMint.toString(), + maker: "5dMXLJ8GYQxcHe2fjpttVkEpRrxcajRXZqJHCiCbWS4H", + payer: "5dMXLJ8GYQxcHe2fjpttVkEpRrxcajRXZqJHCiCbWS4H", + params: { + makingAmount: "1000000", + takingAmount: "300000", + // expiredAt: "", // In unix seconds (e.g. Date.now()/1_000) or optional + // feeBps: "", // Requires referral account or optional + }, + computeUnitPrice: "auto", + // referral: "", // Optional but if specified it is the referral token account of the output mint + inputTokenProgram: inputMintTokenProgram, // Default to token program if empty or specify e.g. token2022 program + outputTokenProgram: outputMintTokenProgram, // same as above + // wrapAndUnwrapSol: true, // Default true or optional + }) + }) +).json(); + +console.log(createOrderResponse); +``` + +From the above example, you should see this sample response. + +```json +{ + order: 'CFG9Bmppz7eZbna96UizACJPYT3UgVgps3KkMNNo6P4k', + tx: 'AQAAAAAAAAAAAAAAAAAAAAAA......AgAKCAkBAQsPAAADBAEMCwcKCQkIBg0LIoVuSq9wn/WfdskdmHlfUulAQg8AAAAAAICpAwAAAAAAAAAJAwEAAAEJAA==' +} +``` + +## Send Limit Order Transaction + +This step is the same as what we do in Swap API, you can read more about how to reformat the serialized create order response, sign and send to the network. + +[We recommend you to read that walkthrough to understand better.](../100-swap-api/3-send-swap-transaction.md) + +```jsx +const transactionBase64 = createOrderResponse.tx +const transaction = VersionedTransaction.deserialize(Buffer.from(transactionBase64, 'base64')); + +transaction.sign([wallet.payer]); + +const transactionBinary = transaction.serialize(); + +const signature = await connection.sendRawTransaction(transactionBinary, { + maxRetries: 2, + skipPreflight: true +}); + +const confirmation = await connection.confirmTransaction({ signature }, "finalized"); + +if (confirmation.value.err) { + throw new Error(`Transaction failed: ${JSON.stringify(confirmation.value.err)}\n\nhttps://solscan.io/tx/${signature}/`); +} else console.log(`Transaction successful: https://solscan.io/tx/${signature}/`); +``` + +## View Open Orders + +This is a GET request to `/openOrders` endpoint. Underneath it, we are proxying the [getProgramAccounts](https://solana.com/docs/rpc/http/getprogramaccounts) RPC method and returning all order accounts associated to the specified wallet account. + +:::tip +You can optionally pass in the input and output token mint addresses to filter the open orders. +::: + +```jsx +const openOrderResponse = await ( + await fetch( + 'https://api.jup.ag/limit/v2/openOrders?wallet=ReplaceWithWallet' + ) +).json(); + +console.log(openOrderResponse); +``` + +An example response is as such. + +```json +[ + { + account: { + borrowMakingAmount: '0', + createdAt: '2024-11-20T07:40:56.000Z', + expiredAt: null, + makingAmount: '1000000', + oriMakingAmount: '1000000', + oriTakingAmount: '240000', + takingAmount: '240000', + uniqueId: '18070363443762671260', + updatedAt: '1732088456', + feeAccount: 'APWoLnZc8g8iXLA8qLdHJ4w42ybRrq2Vm8UGQhH7TJ3r', + inputMint: 'So11111111111111111111111111111111111111112', + inputMintReserve: 'HGeoc1bAvfSCWjMZi3brwv9t76J9s8GBWAL1a9SQ4qgk', + inputTokenProgram: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + maker: ..., + outputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', + outputTokenProgram: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + feeBps: 10, + bump: 255 + }, + publicKey: AccountOrderPublicKey + }, + { + account: { + borrowMakingAmount: '0', + createdAt: '2024-11-20T07:48:29.000Z', + expiredAt: null, + makingAmount: '1000000', + oriMakingAmount: '1000000', + oriTakingAmount: '240000', + takingAmount: '240000', + uniqueId: '17052427428481482637', + updatedAt: '1732088909', + feeAccount: 'APWoLnZc8g8iXLA8qLdHJ4w42ybRrq2Vm8UGQhH7TJ3r', + inputMint: 'So11111111111111111111111111111111111111112', + inputMintReserve: '6oQUyifngb4tgZ1gEmirw4keFB1LeEE2tkoVEj3tu7Ee', + inputTokenProgram: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + maker: ..., + outputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', + outputTokenProgram: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + feeBps: 10, + bump: 254 + }, + publicKey: AccountOrderPublicKey + } +] +``` + +## Cancel Limit Order Transaction + +This is a POST request to `/cancelOrder` endpoint. This will also return with the serialized transaction to be signed by the order account owner and then sent to the network. You will need to pass in the exact public keys of your open orders to cancel them, so you might need to use the `/openOrders` endpoint to get the public keys or other methods if you have a user interface. + +:::tip +If no orders are specified, the API would return the serialized transactions to cancel **ALL** open orders, batched in groups of 5 orders. +::: + +#### Fetch open orders data to get pubkeys + +```jsx +const openOrderResponse = await ( + await fetch( + 'https://api.jup.ag/limit/v2/openOrders?wallet=ReplaceWithWallet' + ) +).json(); +``` + +#### Choose what orders to cancel +If you have a user interface, you will need to have the user choose the order to cancel and then pass its pubkey in here. For example sake, we will just slice the array of pubkeys to take the first in the array. + +```jsx +// To CANCEL ALL orders, pass in the entire array of public keys or do not pass in any +const publicKeys = openOrderResponse.map(item => item.publicKey); + +// To CANCEL SPECIFIC orders, select specific public keys but keep it as an array to be passed in +const publicKeyToCancelArray = publicKeys.slice(0, 1); + +console.log(publicKeyToCancelArray); +``` + +#### Build cancel order transaction(s) + +```jsx +const cancelOrderResponse = await ( + await fetch('https://api.jup.ag/limit/v2/cancelOrders', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + // 'x-api-key': '' // enter api key here + }, + body: JSON.stringify({ + maker: "5dMXLJ8GYQxcHe2fjpttVkEpRrxcajRXZqJHCiCbWS4H", + computeUnitPrice: "auto", + orders: publicKeyToCancelArray, // a list of order accounts, if non are passed in, it will attempt to cancel ALL + }) + }) +).json(); + +console.log(cancelOrderResponse); +``` + +An example response is as such. Then take the serialized transaction response and follow the steps to [sign and send to the network](#send-limit-order-transaction). + +```json +// Open orders response +[ + { + account: { + borrowMakingAmount: '0', + createdAt: '2024-11-20T10:32:20.000Z', + expiredAt: null, + makingAmount: '1000000', + oriMakingAmount: '1000000', + oriTakingAmount: '300000', + takingAmount: '300000', + uniqueId: '12459093665923607188', + updatedAt: '1732098740', + feeAccount: 'APWoLnZc8g8iXLA8qLdHJ4w42ybRrq2Vm8UGQhH7TJ3r', + inputMint: 'So11111111111111111111111111111111111111112', + inputMintReserve: 'HbaSeXEBMDsdHz7GtNoMjRZVN8nZ9CAdjhgBAngBhZhX', + inputTokenProgram: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + maker: Wallet, + outputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', + outputTokenProgram: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + feeBps: 10, + bump: 255 + }, + publicKey: AccountOrderPublicKey0 + }, + { + account: { + borrowMakingAmount: '0', + createdAt: '2024-11-20T10:37:36.000Z', + expiredAt: null, + makingAmount: '1000000', + oriMakingAmount: '1000000', + oriTakingAmount: '300000', + takingAmount: '300000', + uniqueId: '11785358119410645298', + updatedAt: '1732099056', + feeAccount: 'APWoLnZc8g8iXLA8qLdHJ4w42ybRrq2Vm8UGQhH7TJ3r', + inputMint: 'So11111111111111111111111111111111111111112', + inputMintReserve: 'ARnUVsGURQMvkmQ684Uko8U2pFhC4dXjw8fNZt7fLQ6G', + inputTokenProgram: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + maker: Wallet, + outputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', + outputTokenProgram: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + feeBps: 10, + bump: 255 + }, + publicKey: AccountOrderPublicKey1 + } +] + +// Console log publicKeys +[ + 'AccountOrderPublicKey0', + 'AccountOrderPublicKey1' +] + +// Console log publicKeyToCancelArray +[ 'AccountOrderPublicKey0' ] + +// Console log cancelOrderResponse +{ + txs: [ + 'AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA......FWPqnIQMDAAkDvRcoAAAAAAADAAUCY10AAAQJAAABAgQFBgcECF+B7fAIMd+EAA==' + ] +} +``` + +## View Order History + +This is a GET request to `/orderHistory` endpoint. The response is paginated for every 10 orders and you can view different pages using the `page` parameter. The `hasMoreData` boolean will indicate if you have more data in the next page. + +```jsx +const orderHistoryResponse = await ( + await fetch( + 'https://api.jup.ag/limit/v2/orderHistory?wallet=ReplaceWithWallet&page=1' + ) +).json(); + +console.log(orderHistoryResponse); +``` + +An example response is as such. + +```json +{ + orders: [ + { + userPubkey: 'Wallet', + orderKey: 'AccountOrderPublicKey', + inputMint: 'So11111111111111111111111111111111111111112', + outputMint: '6SUryVEuDz5hqAxab6QrGfbzWvjN8dC7m29ezSvDpump', + makingAmount: '3.599980699', + takingAmount: '119999.356633', + remainingMakingAmount: '0', + remainingTakingAmount: '0', + expiredAt: null, + createdAt: '2024-07-18T12:01:02Z', + updatedAt: '2024-07-21T03:07:19Z', + status: 'Completed', + openTx: 'OpenTransaction', + closeTx: 'CloseTransaction', + programVersion: 'j1o2qRpjcyUwEvwtcfhEQefh773ZgjxcVRry7LDqg5X', + trades: [Array] + }, + ... 8 other in between ... + { + userPubkey: 'Wallet', + orderKey: 'AccountOrderPublicKey', + inputMint: 'EKEWAk7hfnwfR8DBb1cTayPPambqyC7pwNiYkaYQKQHp', + outputMint: 'So11111111111111111111111111111111111111112', + makingAmount: '65007.744521', + takingAmount: '25.650235771', + remainingMakingAmount: '65007.744521', + remainingTakingAmount: '25.650235771', + expiredAt: null, + createdAt: '2024-06-30T23:23:51Z', + updatedAt: '2024-07-22T07:31:27Z', + status: 'Cancelled', + openTx: 'OpenTransaction', + closeTx: 'CloseTransaction', + programVersion: 'j1o2qRpjcyUwEvwtcfhEQefh773ZgjxcVRry7LDqg5X', + trades: [] + } + ], + hasMoreData: true, + page: 1 +} +``` + +## Best Practices + +The Limit Order program has some caveats. + +| Item | Recommendation | +| --- | --- | +| The LO program will accept any value to create an order. | On jup.ag, our frontend enforces a minimum of 5 USD per order to be created, this will ensure our keepers can accommodate for no loss in transaction fees coverage. However, programatically, if you do not enforce this, the user can still create an order. | +| The LO program does not check the price or rate of the order, and the keeper will execute as instructed. | On our frontend, when user attempts to set the rate to buy above market price, we provide warnings and disable the execution if above 5%.

If the order is created with such rates, the keeper will execute as instructed. For example, if user sets to Sell 1000 USDC to Buy 1 SOL at the rate of 1000 SOL/USDC, the keeper will execute as instructed and the additional funds will be lost. | +| Tokens with transfer tax extension are disabled. | Our frontend informs the user if the token has transfer tax. | \ No newline at end of file diff --git a/docs/100-swap-api/2-build-swap-transaction.mdx b/docs/100-swap-api/2-build-swap-transaction.mdx new file mode 100644 index 00000000..8f241f52 --- /dev/null +++ b/docs/100-swap-api/2-build-swap-transaction.mdx @@ -0,0 +1,337 @@ +--- +sidebar_label: "Build Swap Transaction" +description: "Jupiter Swap API helps you to build your swap transaction using the quote." +title: "Build Swap Transaction" +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + Build Swap Transaction + + + +The Swap API is one of the ways for you to interact with the Jupiter Swap Aggregator program. Before you send a transaction to the network, you will need to build the transaction that defines the instructions to execute and accounts to read/write to. + +It can be complex to handle this yourself, but good news! Most of our APIs and SDKs just handles it for you, so you get a response with the transaction to be prepared and sent to the network. + +:::tip Use Swap API to handle it for you or ... + +If you are looking to interact with the Jupiter Swap Aggregator program in a different way, check out the other guides: + +#### Swap Instructions +To compose with instructions and build your own transaction, [read how to use the `/swap-instructions` in this section](#build-your-own-transaction-with-instructions). + +#### Flash Fill or Cross Program Invocation (CPI) +To interact with your own Solana program, [read how to use the **Flash Fill method** or **CPI** in this section](#build-your-own-transaction-with-flash-fill-or-cpi). +::: + +## Let’s Get Started + +In this guide, we will pick up from where [**Get Quote**](./1-get-quote.md) guide has left off. + +If you have not set up your environment to use the necessary libraries, the RPC connection to the network and successfully get a quote from the Quote API, please start at [get started](../1-get-started.md) or [get quote](./1-get-quote.md). + +:::tip API Reference +To fully utilize the Swap API, check out the [Swap API Reference](/docs/api/swap) or [Swap Instructions Reference](/docs/api/swap-instructions). +::: + +## Swap API + +The root URL of the Swap API is as such. + +```markdown +https://api.jup.ag/swap/v1 +``` + +From the previous guide on getting a quote, now using the quote response and your wallet, you can receive a **serialized swap transaction** that can be needs to be prepared and signed before sending to the network. + +## Get Serialized Transaction + +Using the root URL and parameters to pass in, it is as simple as the example code below! + +:::tip Optimizing for Transaction Landing is super super important! +This code block includes additional parameters that our Swap API supports, such as estimating compute units, priority fees and slippage, to optimize for transaction landing. + +To understand how these parameters help, the next step, [Send Swap Transaction guide](./3-send-swap-transaction.md) will discuss them. +::: + +```jsx +const swapResponse = await ( +await fetch('https://api.jup.ag/swap/v1', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + // 'x-api-key': '' // enter api key here + }, + body: JSON.stringify({ + quoteResponse, + userPublicKey: wallet.publicKey.toString(), + + // ADDITIONAL PARAMETERS TO OPTIMIZE FOR TRANSACTION LANDING + // See next guide to optimize for transaction landing + dynamicComputeUnitLimit: true, + dynamicSlippage: true, + prioritizationFeeLamports: { + priorityLevelWithMaxLamports: { + maxLamports: 1000000, + priorityLevel: "veryHigh" + } + } + }) +}) +).json(); + +console.log(swapResponse); +``` + +From the above example, you should see this response. + +```json +{ + swapTransaction: 'AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAGDkS+3LuGTbs......+/oD9qb31dH6i0QZ2IHELXUX3Y1YeW79p9Stkqk12z4yvZFJiQ4GCQwLBwYQBgUEDggNTQ==', + lastValidBlockHeight: 279632475, + prioritizationFeeLamports: 9999, + computeUnitLimit: 388876, + prioritizationType: { + computeBudget: { + microLamports: 25715, + estimatedMicroLamports: 785154 + } + }, + dynamicSlippageReport: { + slippageBps: 50, + otherAmount: 20612318, + simulatedIncurredSlippageBps: -18, + amplificationRatio: '1.5', + categoryName: 'lst', + heuristicMaxSlippageBps: 100 + }, + simulationError: null +} +``` + +## What’s Next + +Now, you are able to get a quote and use our Swap API to build the swap transaction for you. Next steps is to proceed to prepare and sign the transaction and send the signed transaction to the network. + +**[Let’s go sign and send!](./3-send-swap-transaction.md)** + +--- + +## Additional Resources + +### Build Your Own Transaction With Instructions + +If you may prefer to compose with instructions instead of the provided transaction that is returned from the `/swap` endpoint (like the above example). You can post to `/swap-instructions` instead, it takes the same parameters as the `/swap` endpoint but returns you the instructions rather than the serialized transaction. + +
+ +
+
+ /swap-instructions code snippet +
+
+
+Example code snippet of using `/swap-instruction` + +```jsx +const instructions = await ( + await fetch('https://api.jup.ag/swap-instructions/v1', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + quoteResponse, + userPublicKey: wallet.publicKey.toString(), + }) + }) +).json(); + +if (instructions.error) { + throw new Error("Failed to get swap instructions: " + instructions.error); +} + +const { + tokenLedgerInstruction, // If you are using `useTokenLedger = true`. + computeBudgetInstructions, // The necessary instructions to setup the compute budget. + setupInstructions, // Setup missing ATA for the users. + swapInstruction: swapInstructionPayload, // The actual swap instruction. + cleanupInstruction, // Unwrap the SOL if `wrapAndUnwrapSol = true`. + addressLookupTableAddresses, // The lookup table addresses that you can use if you are using versioned transaction. +} = instructions; + +const deserializeInstruction = (instruction) => { + return new TransactionInstruction({ + programId: new PublicKey(instruction.programId), + keys: instruction.accounts.map((key) => ({ + pubkey: new PublicKey(key.pubkey), + isSigner: key.isSigner, + isWritable: key.isWritable, + })), + data: Buffer.from(instruction.data, "base64"), + }); +}; + +const getAddressLookupTableAccounts = async ( + keys: string[] +): Promise => { + const addressLookupTableAccountInfos = + await connection.getMultipleAccountsInfo( + keys.map((key) => new PublicKey(key)) + ); + + return addressLookupTableAccountInfos.reduce((acc, accountInfo, index) => { + const addressLookupTableAddress = keys[index]; + if (accountInfo) { + const addressLookupTableAccount = new AddressLookupTableAccount({ + key: new PublicKey(addressLookupTableAddress), + state: AddressLookupTableAccount.deserialize(accountInfo.data), + }); + acc.push(addressLookupTableAccount); + } + + return acc; + }, new Array()); +}; + +const addressLookupTableAccounts: AddressLookupTableAccount[] = []; + +addressLookupTableAccounts.push( + ...(await getAddressLookupTableAccounts(addressLookupTableAddresses)) +); + +const blockhash = (await connection.getLatestBlockhash()).blockhash; +const messageV0 = new TransactionMessage({ + payerKey: payerPublicKey, + recentBlockhash: blockhash, + instructions: [ + // uncomment if needed: ...setupInstructions.map(deserializeInstruction), + deserializeInstruction(swapInstructionPayload), + // uncomment if needed: deserializeInstruction(cleanupInstruction), + ], +}).compileToV0Message(addressLookupTableAccounts); +const transaction = new VersionedTransaction(messageV0); +``` +
+ +### Build Your Own Transaction With Flash Fill Or CPI + +If you may prefer to interact with the Jupiter Swap Aggregator program with your own on-chain program. There are 2 ways to do it, typically on-chain program call **Cross Program Invocation (CPI)** to interact with each other, but we recommend using the **Flash Fill method** built by Jupiter. + +:::tip Why Flash Fill? + +With Jupiter's complex routing, best prices comes at a cost. It often means more compute resources and accounts are required as it would route across multiple DEXes in one transaction. + +Solana transactions are limited to 1232 bytes, Jupiter is using Address Lookup Tables (ALTs) to include more accounts in one transaction. However, the CPI method cannot use ALTs, which means when you add more accounts to a Jupiter Swap transaction, it will likely fail if it exceeds the transaction size limits. + +**Flash Fill allows the use of Versioned Transaction and ALTs**, hence, reducing the total accounts used for a Jupiter Swap transaction. +::: + +
+ +
+
+ Flash Fill and CPI references +
+
+
+ + + A Flash Fill transaction will be composed of these instructions: +
    +
  1. Borrow enough SOL for opening the wSOL account from this program.
  2. +
  3. Create the wSOL account for the borrower.
  4. +
  5. Swap X token to wSOL.
  6. +
  7. Close the wSOL account and send it to the borrower.
  8. +
  9. Repay the SOL for opening the wSOL account back to this program.
  10. +
+ Links and resources: + +
+ + A CPI transaction will be composed of these instructions: +
    +
  1. Borrow enough SOL from the program to open a wSOL account that the program owns.
  2. +
  3. Swap X token from the user to wSOL on Jupiter via CPI.
  4. +
  5. Close the wSOL account and send it to the program.
  6. +
  7. The program then transfers the SOL back to the user.
  8. +
+ Links and resources: + +
+ +
+
+ To ease integration via CPI, you may add the following crate jupiter-cpi to your program. +
+
+
+ In cargo.toml
+
+                    
+{`[dependencies]
+jupiter-cpi = { git = "https://github.com/jup-ag/jupiter-cpi", rev = "5eb8977" }
+... other dependencies
+`}
+                    
+                
+ In your code
+
+                    
+{`use jupiter_cpi;\n
+...\n
+let signer_seeds: &[&[&[u8]]] = &[...];\n
+// Pass accounts to context one-by-one and construct accounts here.
+// Or in practise, it may be easier to use remaining_accounts https://book.anchor-lang.com/anchor_in_depth/the_program_module.html\n
+let accounts = jupiter_cpi::cpi::accounts::SharedAccountsRoute {
+    token_program: ,
+    program_authority: ,
+    user_transfer_authority: ,
+    source_token_account: ,
+    program_source_token_account: ,
+    program_destination_token_account: ,
+    destination_token_account: ,
+    source_mint: ,
+    destination_mint: ,
+    platform_fee_account: ,
+    token_2022_program: ,
+};\n
+let cpi_ctx = CpiContext::new_with_signer(
+    ctx.accounts.jup.to_account_info(),
+    accounts,
+    signer_seeds,
+);\n
+jupiter_cpi::cpi::shared_accounts_route(
+    cpi_ctx,
+    id,
+    route_plan,
+    in_amount,
+    quoted_out_amount,
+    slippage_bps,
+    platform_fee_bps,
+)?;\n
+...
+`}
+                    
+                
+
+
+
+
diff --git a/docs/100-swap-api/200-dca-sdk.md b/docs/100-swap-api/200-dca-sdk.md new file mode 100644 index 00000000..6e3ce4be --- /dev/null +++ b/docs/100-swap-api/200-dca-sdk.md @@ -0,0 +1,14 @@ +--- +sidebar_label: "DCA SDK" +description: "Use the Jupiter DCA SDK to create/cancel orders." +title: "DCA SDK" +--- + + + DCA SDK + + + +:::warning +We are working on improving the DCA program and the documentation will be improved in the future too. If you plan to or still use the current DCA SDK, [please refer to the documentation here](../../docs_versioned_docs/version-old/4-dca/1-integration.md) +::: diff --git a/docs/100-swap-api/3-send-swap-transaction.md b/docs/100-swap-api/3-send-swap-transaction.md new file mode 100644 index 00000000..10643f88 --- /dev/null +++ b/docs/100-swap-api/3-send-swap-transaction.md @@ -0,0 +1,276 @@ +--- +sidebar_label: "Send Swap Transaction" +description: "Jupiter Swap API helps you to optimize sending transaction to the network." +title: "Send Swap Transaction" +--- + + + Send Swap Transaction + + + +Transaction sending can be very simple but optimizing for transaction landing can be challenging. This is critical in periods of network congestion when many users and especially bots are competing for block space to have their transactions processed. + +:::tip Improve Transaction Landing Tip +By using Jupiter Swap API, you can enable Dynamic Slippage, Priority Fee estimation and Compute Unit estimation, all supported on our backend and served directly to you through our API. +::: + +## Let’s Get Started + +In this guide, we will pick up from where [**Get Quote**](./1-get-quote.md) and [**Build Swap Transaction**](./2-build-swap-transaction.mdx) guide has left off. + +If you have not set up your environment to use the necessary libraries, the RPC connection to the network and successfully get a quote from the Quote API, please start at [get started](../1-get-started.md) or [get quote](./1-get-quote.md). + +## Prepare Transaction + +:::info Who is the signer? +The most important part of this step is to sign the transaction. For the sake of the guide, you will be using the file system wallet you have set up to sign and send yourself. + +However, for other production scenarios such as building your own program or app on top of the Swap API, you will need the user to be the signer which is often through a third party wallet provider, so do account for it. +::: + +In the previous guide, we are able to get the `swapTransaction` from the Swap API response. However, you will need to reformat it to sign and send the transaction, here are the formats to note of. + +| Formats | Description | +|---------|-------------| +| Serialized Uint8array format | The correct format to send to the network. | +| Serialized base64 format | This is a text encoding of the Uint8array data, meant for transport like our Swap API or storage. You should not sign this directly. | +| Deserialized format | This is the human-readable, object-like format before serialization. This is the state you will sign the transaction. | + +Here's the code to deserialize and sign, then serialize. +1. `swapTransaction` from the Swap API is a serialized transaction in the **base64 format**. +2. Convert it to **Uint8array (binary buffer) format**. +3. Deserialize it to a **VersionedTransaction** object to sign. +4. Finally, convert it back to **Uint8array** format to send the transaction. + +```jsx +const transactionBase64 = swapResponse.swapTransaction +const transaction = VersionedTransaction.deserialize(Buffer.from(transactionBase64, 'base64')); +console.log(transaction); + +transaction.sign([wallet.payer]); + +const transactionBinary = transaction.serialize(); +console.log(transactionBinary); +``` + +:::tip Blockhash Validity +If you look at the response of `console.log(transaction);`, you can see that our backend has already handled the blockhash and last valid block height in your transaction. + +The validity of a blockhash typically lasts for 150 slots, but you can manipulate this to reduce the validity of a transaction, resulting in faster failures which could be useful in certain scenarios. + +[Read more about transaction expiry here.](https://solana.com/docs/advanced/confirmation#transaction-expiration) +::: + +## Send Transaction + +### Transaction Sending Options + +Finally, there are a 2 [transaction sending options](https://solana.com/docs/advanced/retry#an-in-depth-look-at-sendtransaction) that we should take note of. Depending on your use case, these options can make a big difference to you or your users. For example, if you are using the Swap API as a payment solution, setting higher `maxRetries` allows the transaction to have more retries as it is not as critical compared to a bot that needs to catch fast moving markets. + +
+ +
+
+ Transaction Sending Options +
+
+
+ +| Options | Description | +|---------|-------------| +| [maxRetries](https://solana.com/docs/advanced/retry) | Maximum number of times for the RPC node to retry sending the transaction to the leader. If this parameter is not provided, the RPC node will retry the transaction until it is finalized or until the blockhash expires. | +| [skipPreflight](https://solana.com/docs/advanced/retry#the-cost-of-skipping-preflight) | If true, skip the preflight transaction checks (default: false).

| + +
+ + +```jsx +const signature = await connection.sendRawTransaction(transactionBinary, { + maxRetries: 2, + skipPreflight: true +}); +``` + +### Transaction Confirmation + +In addition, after sending the transaction, it is always a best practice to check the transaction confirmation state, and if not, log the error for debugging or communicating with your users on your interface. [Read more about transaction confirmation tips here.](https://solana.com/docs/advanced/confirmation#transaction-confirmation-tips) + +```jsx +const confirmation = await connection.confirmTransaction({signature,}, "finalized"); + +if (confirmation.value.err) { + throw new Error(`Transaction failed: ${JSON.stringify(confirmation.value.err)}\nhttps://solscan.io/tx/${signature}/`); +} else console.log(`Transaction successful: https://solscan.io/tx/${signature}/`); +``` + +## Swap Transaction Executed! + +If you have followed the guides step by step without missing a beat, your transaction *should* theoretically land and you can view the link in console log to see the [transaction](https://solscan.io/tx/zEWGsd5tSyxUdsTn27hUzaJBadQSiFxF2X1CxVdQzdtgc3BpqyDPf5VQCFUScidhHJP5PchY33oJ3tZJLK5KXrf). + +## Oh? Transaction Not Landing? + +As the Solana network grew and increased in activty over the years, it has become more challenging to land transactions. There are several factors that can drastically affect the success of your transaction: + +- Setting competitive priority fee +- Setting accurate amount of compute units +- Managing slippage effectively +- Broadcasting transaction efficiently +- Other tips + +### How Jupiter Estimates Priority Fee? + +You can pass in `prioritizationFeeLamports` to Swap API where our backend will estimate the Priority Fee for you. + +We are using [Triton’s `getRecentPrioritizationFees`](https://docs.triton.one/chains/solana/improved-priority-fees-api) to estimate using the local fee market in writable accounts of the transaction (comparing to the global fee market), across the past 20 slots and categorizing them into different percentiles. + +[Read more about Priority Fee here.](https://solana.com/docs/core/fees#prioritization-fees) + +| Parameters | Description | +|------------|-------------| +| `maxLamports` | A maximum cap applied if the estimated priority fee is too high. This is helpful when you have users using your application and can be a safety measure to prevent overpaying. | +| `global` | A boolean to decide between to use global or local fee market to estimate. If `global` is set to `false`, the estimation focuses on fees relevant to the **writable accounts** involved in the instruction. | +| `priorityLevel` | A setting to choose between the different percentile levels. Higher percentile will have better transaction landing but also incur higher fees.

| + +```jsx +const swapResponse = await ( + await fetch('https://api.jup.ag/swap/v1', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + quoteResponse, + userPublicKey: wallet.publicKey.toBase58(), + prioritizationFeeLamports: { + priorityLevelWithMaxLamports: { + maxLamports: 10000000, + global: false, + priorityLevel: "veryHigh" + } + } + }) + }) +).json(); +``` + +### How Jupiter Estimates Compute Unit Limit? + +You can pass in `dynamicComputeUnitLimit` to Swap API where our backend will estimate the Compute Unit Limit for you. + +When `true`, it allows the transaction to utilize a dynamic compute unit rather than using incorrect compute units which can be detrimental to transaction prioritization. Additionally, the amount of compute unit used and the compute unit limit requested to be used are correlated to the amount of priority fees you pay. + +[Read more about Compute Budget, Compute Unit, etc here.](https://solana.com/docs/core/fees#compute-budget) + +```jsx +const swapTransaction = await ( + await fetch('https://api.jup.ag/swap/v1', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + quoteResponse, + userPublicKey: wallet.publicKey.toBase58(), + dynamicComputeUnitLimit: true + }) + }) +).json(); +``` + +### How Jupiter Estimates Slippage? + +You can pass in `dynamicSlippage` to Swap API where our backend will estimate the a dynamic slippage to be used for this specific quote and transaction for you. + +When `true` is passed in, it allows our backend to simulate slippage closer to execution and calculate an optimal value based on the token category, heuristics. + +:::note +To understand Dynamic Slippage better, you can read here: +- [Jupresearch](https://www.jupresear.ch/t/dynamic-slippage/21946#p-37444-introducing-dynamic-slippage-1) +- [Dynamic Slippage Config](https://github.com/jup-ag/dynamic-slippage-config) +::: + +```jsx +const swapTransaction = await ( + await fetch('https://api.jup.ag/swap/v1', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + quoteResponse, + userPublicKey: wallet.publicKey.toBase58(), + dynamicSlippage: true, + }) + }) +).json(); +``` + +The Swap API response will return the serialized transaction which will be using the dynamic slippage value and a `dynamicSlippageReport` for visibility/error catching. + +```json +{ + "swapTransaction": "...", + "dynamicSlippageReport": { + "slippageBps": 12, // The final optimized slippage bps used in the serialized transaction + "otherAmount": 8759842, // The incurred out amount observed from simulating the transaction + "simulatedIncurredSlippageBps": -8, // The simulated incurred slippage during optimization (negative integer refers to the loss in bps while positive refers to the gain) + "amplificationRatio": "1.5" // An amplifcation ratio we use to add a buffer to the estimated slippage + }, + "simulationError": null +} +``` + +### How Jupiter Broadcast Transactions? + +Transaction broadcasting is the process of submitting a signed transaction to the network so that validators can verify, process, and include it in a block. + +#### Broadcasting Through RPCs + +After you’ve built and signed your transaction, the signed transaction is serialized into a binary format and sent to the network via a Solana RPC node. The RPC node will verify and relay the transaction to the leader validator responsible for producing the next block. + +[Read more about how RPC nodes broadcast transactions.](https://solana.com/docs/advanced/retry#how-rpc-nodes-broadcast-transactions) + +This is the most typical method to send transactions to the network to get executed. It is simple but you need to make sure the transactions are: +- Send in the serialized transaction format. +- Use fresh blockhash and last valid blockheight. +- Use optimal amount of priority fees and compute unit limit. +- Free of error. +- Utilize retries. +- Configure your RPCs + - Optional but you can send your transaction to a staked RPC endpoint also known as [Stake-Weighted Quality of Service (SWQoS)](https://solana.com/developers/guides/advanced/stake-weighted-qos). + - Used dedicated RPC services versus free or shared, depending on how critical your usage is. + - Propagate to multiple RPC rather than reliant on one. + + +#### Broadcasting Through Jito + +To include Jito Tips in your Swap transaction, you can do specify in the Swap API parameters. However, please take note of these when sending your transaction to Jito and [you can find thsese information in their documentation](https://docs.jito.wtf/): +- You need to submit to a Jito RPC endpoint for it to work. +- You need to send an appropriate amount of Jito Tip to be included to be processed. + +:::note More about Jito +You can leverage [Jito](https://www.jito.wtf/) to send transactions via tips for faster inclusion and better outcomes. Similar to Priority Fees, Jito Tips incentivize the inclusion of transaction bundles during block production, enhancing users' chances of securing critical transactions in competitive scenarios. + +Additionally, Jito enables bundling transactions to ensure they execute together or not at all, helping protect against front-running and other MEV risks through “revert protection” if any part of the sequence fails, all while reducing transaction latency for timely execution. + +[Read more about how Jito works and other details here.](https://docs.jito.wtf/lowlatencytxnsend/#system-overview) +::: + +```jsx +const swapTransaction = await ( + await fetch('https://api.jup.ag/swap/v1', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + quoteResponse, + userPublicKey: wallet.publicKey.toBase58(), + prioritizationFeeLamports: { + jitoTipLamports: 1000000 // note that this is FIXED LAMPORTS not a max cap + } + }) + }) +).json(); +``` \ No newline at end of file diff --git a/docs/100-swap-api/4-add-fees-to-swap.md b/docs/100-swap-api/4-add-fees-to-swap.md new file mode 100644 index 00000000..4143008a --- /dev/null +++ b/docs/100-swap-api/4-add-fees-to-swap.md @@ -0,0 +1,143 @@ +--- +sidebar_label: "Add Fees To Swap" +description: "Jupiter Swap API allows you to add fees." +title: "Add Fees To Swap" +--- + + + Add Fees To Swap + + + +The Referral Program is an open source program by Jupiter to provide referral fees for integrators who are integrating Jupiter Swap and Jupiter Limit Order. You can check out the code [here](https://github.com/TeamRaccoons/referral) to gain a better understanding of how it works. + +## Use Case + +By default, there are **zero** protocol fees on Jupiter Swap. Integrators have the option to introduce a platform fee denoted in basis points, e.g. **20 bps** for **0.2%** of the token input or output. If a platform fee is set by an integrator, Jupiter will **take 2.5%** of the platform fee charged by the integrators. + +:::note +If you use our APIs heavily and consider taking fees, please reach out to us. +::: + +### Important Notes + +- This is useful if you are an end user application such as wallets, payments, merchants, etc. +- The Jupiter Swap project account for the Referral Program is `45ruCyfdRkWpRNGEqWzjCiXRHkZs8WXCLQ67Pnpye7Hp`. +- The `referralTokenAccount` can either be: + - **Input mint or the output mint** on the swap for ExactIn. + - **Input mint ONLY** on the swap for ExactOut. +- You can use the [Dashboard](https://referral.jup.ag/dashboard), [SDK](https://github.com/TeamRaccoons/referral/blob/main/example/src/createReferralAccount.ts) or [API](https://referral.jup.ag/api) to set up the `referralAccount` and `referralTokenAccount` in this guide. +- It does not support Token2022 tokens. + +## Let’s Get Started + +### 1. Set up + +You will need to complete the prerequisites and understanding of [Get Started](../1-get-started.md) and [Get Quote and Swap](1-get-quote.md) guide as this is reliant on the Swap API. + +**Obtain `referralAccount` and `referralTokenAccount`** + +There are 3 ways you can set up a referral account. + +1. Use our [referral dashboard](https://referral.jup.ag/dashboard) to create them. After creating, remember to find your `Referral Key` on the page and the associated token accounts. +2. Use our SDK to create them. You can use the [example scripts](https://github.com/TeamRaccoons/referral/tree/main/example/src) to create. +3. Use our API to create them. You can use this [API reference](https://referral.jup.ag/api) to create. + +**Obtain `mintAccount`** + +As for the mint account, assuming you have an interface where a user swaps, you will know up front what are the input or output mints. For the sake of example, we will use a hardcoded mint public key. + +```jsx +const referralAccount = new Publickey('ReplaceWithPubkey'); +const mintAccount = new Publickey('So11111111111111111111111111111111111111112'); +``` + +### 3. Set your referral fee in Quote + +Setting your referral fee is simple, just add `platformFeeBps` parameter to the `/quote` endpoint. + +In this example, we set `platformFeeBps` to `20` which equates to 0.2%. + +```jsx +const quoteResponse = await ( + await fetch( + 'https://api.jup.ag/quote/v1?inputMint=So11111111111111111111111111111111111111112&outputMint=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v&amount=100000&slippageBps=50&restrictIntermediateTokens=true&platformFeeBps=20' + ) + ).json(); + +console.log(JSON.stringify(quoteResponse, null, 2)); +``` + +### 3. Set your referral token account in Swap + +In order to refer and receive fees from all types of tokens, you will need to have already initialize `referralTokenAccount`s (owned by your `referralAccount`) for the mint in the swap. By calling the Swap API with the parameter `feeAccount`, which is the `referralTokenAccount`, you will receive the serialized swap transaction that will set a fee to be taken from the referred and sent to that token account. + +In this code block, we will be using the SDK to try to find the `referralTokenAccount` based on our previously defined `referralAccount` and `mintAccount`. +- If the token account is found, it will proceed to the Swap API. +- If the token account is not found, it will send a transaction to the network to attempt to initialize one for the mint. **Do note that transactions may fail due to various reasons like Priority Fees.** + +```jsx +import { ReferralProvider } from "@jup-ag/referral-sdk"; + +const { tx, referralTokenAccountPubKey } = await provider.initializeReferralTokenAccount({ + payerPubKey: wallet.publicKey, + referralAccountPubKey: referralAccount, + mint: mintAccount, +}); + +const referralTokenAccount = await connection.getAccountInfo(referralTokenAccountPubKey); + +// Attempt to initialize a token account +if (!referralTokenAccount) { + const signature = await sendAndConfirmTransaction(connection, tx, [wallet]); + console.log({ signature, referralTokenAccountPubKey: referralTokenAccountPubKey.toBase58() }); + +// Since initialized, it will carry on +} else { + console.log(`referralTokenAccount ${referralTokenAccountPubKey.toBase58()} for mint ${mintAccount.toBase58()} already exists`); +}; + +const feeAccount = referralTokenAccountPubKey; +console.log(feeAccount); +``` + +However, if you are confident that the `referralTokenAccount` for specific mints have been created, you can use this method to get it. **Do note that, even if the token account is not intialized, it will return a pubkey as it is a Program Derived Address. [Read more here.](https://solana.com/docs/core/pda#findprogramaddress)** + +```jsx +const [feeAccount] = PublicKey.findProgramAddressSync( + [ + Buffer.from("referral_ata"), // A string that signifies the account type, here "referral_ata." + referralAccount.toBuffer(), // The public key of the referral account converted into a buffer. + mintAccount.toBuffer(), // The mint public key, converted into a buffer. + ], + new PublicKey("REFER4ZgmyYx9c6He5XfaTMiGfdLwRnkV4RPp9t9iF3") // The public key of the Referral Program +); +``` + +Using the above, we will now know the `feeAccount` to be passed in as the parameter in Swap API. You can refer to the [Build Swap Transaction](2-build-swap-transaction.mdx) guide to add any parameters where necessary to help transaction sending, etc. + +```jsx +const swapResponse = await ( + await fetch('https://api.jup.ag/swap/v1', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + quoteResponse, + userPublicKey: wallet.publicKey.toBase58(), // Pass in actual referred user in production + feeAccount: feeAccount, + }) + }) +).json(); + +console.log(swapResponse); +``` + +### 4. Sign and send transaction + +Finally, the referred can sign the transaction and it can be submitted to the network to be executed. You can refer to the [Send Swap Transaction](3-send-swap-transaction.md) guide to complete this step. + +## Additional Resources + +Now you have set up and added fees to the swaps you provide to the end users. The fees are collected and stored in the `referralTokenAccount`. In order to claim them, you can use the SDK or API to claim them all at once. \ No newline at end of file diff --git a/docs/100-swap-api/5-payments-through-swap.md b/docs/100-swap-api/5-payments-through-swap.md new file mode 100644 index 00000000..f91a9820 --- /dev/null +++ b/docs/100-swap-api/5-payments-through-swap.md @@ -0,0 +1,180 @@ +--- +sidebar_label: "Payments Through Swap" +description: "Jupiter Swap API allows you to set up payments solutions for your products." +title: "Payments Through Swap" +--- + + + Payments Through Swap + + + +The Jupiter Swap API can be utilized such that you, a merchant can allow your customer to pay in any tokens while you still receive in your preferred token payment at the end of the transaction. + +## Use Case + +Let’s set the stage. You are selling a **jupcake!!!** to your customer and merchant might only accept in 1 USDC, but Alice only has 1 SOL for various reasons. Well, you’re at the right place! By using the Swap API, merchant can let customer pay in SOL while merchant still receive USDC in order to complete the payment for a jupcake. + +- Customer has 1,000,000 SOL. +- Merchant sells 1 jupcake for 1 USDC. +- Use the Swap API to swap exactly 1 USDC output from Customer's SOL. +- Merchant receives the 1 USDC, as planned! + +## Let’s Get Started + +### 1. Setup + +You will need slightly different imports and also remember to set up connection to an RPC. If you have not set up the other typical libraries or are familiar with the Swap API, please follow this [Get Started](../1-get-started.md) and [Get Quote and Swap](./1-get-quote.md) guide. + +```bash +npm i @solana/spl-token +``` + +```jsx +import { PublicKey, Connection, Keypair, VersionedTransaction } from '@solana/web3.js'; +import { getAssociatedTokenAddress, TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID } from '@solana/spl-token'; +import { Wallet } from '@coral-xyz/anchor'; +import fetch from 'cross-fetch'; +``` + +Before we start getting a quote and swap transaction, for example sake, we will need to prepare your and Alice's accounts. In production scenario, you will need to dynamically pass this in and allow users to sign in their device interfaces. + +Do note that you will need to have already set up: +- A wallet in your machine to simulate yourself as the customer as the customer is the signer of the transaction (similar to how we set up in [Get Started - Set Up Your Wallet](../1-get-started.md#4-set-up-your-wallet)). +- `trackingAccount` is basically an additional Solana Account you can pass in to track only Jupiter transactions easily. + +#### Set Up Accounts + +```jsx +const customerAccount = new Wallet(...); // Follow the method in #get-started + +console.log("customerAccount:", customerAccount.publicKey.toBase58()); + +const USDC_MINT = new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'); // Your preferred token payment + +const merchantAccount = new PublicKey('ReplaceWithMerchantPubkey'); +// const trackingAccount = new PublicKey('ReplaceWithPubkey'); + +console.log("USDC_MINT:", USDC_MINT.toBase58()); +console.log("merchantAccount:", merchantAccount.toBase58()); +// console.log("trackingAccount:", trackingAccount.toBase58()); +``` + +#### Set Up `destinationTokenAccount` + +One more thing you will need to set up! Later on, you will need to pass in `destinationTokenAccount` which will be your token account for your preferred token payment mint. **Do note that it is the merchant's token account and it needs to be initialized.** + +```jsx +// Get the associated token account for the merchant wallet +const merchantUSDCTokenAccount = await getAssociatedTokenAddress( + USDC_MINT, + merchantAccount, + true, + TOKEN_PROGRAM_ID, + ASSOCIATED_TOKEN_PROGRAM_ID +); + +console.log("merchantUSDCTokenAccount:", merchantUSDCTokenAccount.toBase58()); +``` + +### 2. Set `swapMode` to `ExactOut` in Quote + +Next, the merchant have to [Get Quote](./1-get-quote.md) for the customer. We are using the `ExactOut` mode because we know exactly how much output amount (1 USDC) the merchant want to receive but not sure how much input amount the customer should pay with. + +By getting a quote first, the customer can know upfront the specific amount of input token before they approve and sign the transaction. + +:::warning Limitations of `ExactOut` +Currently, there are some limitations as `ExactOut` is not widely supported across all DEXes. +- Supported DEXes are only Orca Whirlpool, Raydium CLMM, and Raydium CPMM. +- NOT ALL token pairs may not be available. +::: + +```jsx +const quoteResponse = await ( + await fetch( + 'https://api.jup.ag/quote/v1?inputMint=So11111111111111111111111111111111111111112&outputMint=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v&amount=100000&slippageBps=50&restrictIntermediateTokens=true&swapMode=ExactOut' + ) + ).json(); + +console.log(JSON.stringify(quoteResponse, null, 2)); +``` + +From the this quote, you should get part of the response like this, where `amount` specified in the query parameter represents the `outAmount` in the response and of course, `swapMode: ExactOut`. + +```json +{ + "inputMint": "So11111111111111111111111111111111111111112", + "inAmount": "4434914", + "outputMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + "outAmount": "1000000", + "otherAmountThreshold": "4434914", + "swapMode": "ExactOut", + ... +} +``` + +### 3. Set `destinationTokenAccount` in Swap + +The merchant then retrieves the serialized swap transaction, but the merchant need to specify the `destinationTokenAccount` in the parameters — this will build the swap transaction to swap but send to the [merchant's specified token account which we defined earlier](#set-up-destinationtokenaccount). + +The `destinationTokenAccount` should be the merchant’s token account to receive the payment in. Also do note that `customerAccount` should be accounted for. **You can refer to the [Build Swap Transaction](./2-build-swap-transaction.mdx) guide for other parameters to be passed in.** + +```jsx +const swapResponse = await ( + await fetch('https://api.jup.ag/swap/v1', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + quoteResponse, + userPublicKey: customerAccount.publicKey.toBase58(), + destinationTokenAccount: merchantUSDCTokenAccount.toBase58(), + // trackingAccount: trackingAccount.toBase58(), + }) + }) +).json(); + +console.log(swapResponse); +``` + +### 4. Prepare Transaction + +We have walked through the steps here and explained some of the code, you can refer to [Send Swap Transaction - Prepare Transaction](./3-send-swap-transaction.md#prepare-transaction). The main difference for payments is to ensure that the customer is the fee payer (the merchant can be generous and be the fee payer too!) and the signer. + +```jsx +const transactionBase64 = swapResponse.swapTransaction +const transaction = VersionedTransaction.deserialize(Buffer.from(transactionBase64, 'base64')); + +transaction.feePayer = customerAccount.publicKey; + +transaction.sign([customerAccount.payer]); + +const transactionBinary = transaction.serialize(); +``` + +### 5. Send Transaction + +We have walked through the steps here and explained some of the code, you can refer to [Send Swap Transaction - Send Transaction](./3-send-swap-transaction.md#send-transaction). The main difference for payments is, you might want to try adjusting `maxRetries` to a higher count as it is not time sensitive and ideally this is used with tighter slippage and ensuring the `inputMint` is not too unstable. + +Do note that more retries will cause the user to wait slightly longer, so find the balance between the two. Read more here: https://solana.com/docs/advanced/retry. + +```jsx +const signature = await connection.sendRawTransaction(transactionBinary, { + maxRetries: 10, + preflightCommitment: "finalized", +}); + +const confirmation = await connection.confirmTransaction({ signature }, "finalized"); + +if (confirmation.value.err) { + throw new Error(`Transaction failed: ${JSON.stringify(confirmation.value.err)}\nhttps://solscan.io/${signature}/`); +} else console.log(`Transaction successful: https://solscan.io/tx/${signature}/`); +``` + +The suceeded Swap Transaction should show: +- Token A swaps from the customer's token account +- Token A swap to Token B +- Token B sends to the merchant's token account + +[If transactions are not landing well, you can refer to this section.](./3-send-swap-transaction.md#oh-transaction-not-landing) diff --git a/docs/100-swap-api/6-solana-unity-sdk.md b/docs/100-swap-api/6-solana-unity-sdk.md new file mode 100644 index 00000000..5b782ce5 --- /dev/null +++ b/docs/100-swap-api/6-solana-unity-sdk.md @@ -0,0 +1,25 @@ +--- +sidebar_label: "Swap In Solana Unity SDK" +description: "Use Jupiter Swap API with Solana Unity SDK (C#) to add Swap into your game." +title: "Swap In Solana Unity SDK (C#)" +--- + + + Solana Unity SDK (C#) + + + +Jupiter is fully supported within the [Solana.Unity-SDK](https://github.com/magicblock-labs/Solana.Unity-Core/tree/master/src/Solana.Unity.Dex). The core library is independent of Unity and can be incorporated into Unreal Engine using the UnrealCLR library or in a C# backend. + +Using the Solana.Unity-SDK, game developers can effortlessly incorporate Jupiter swaps into their games and achieve cross-platform compatibility without the need to modify a single line of code. + +Within the SDK, the Jupiter Swap API can also be used as a [payment method](./5-payments-through-swap.md), enabling you to utilize Jupiter + SolanaPay for facilitating user payments with any SPL token, allowing pricing in USDC or other tokens. + +## Documentation + +For the detailed documentation, please visit: [Solana Unity SDK Jupiter Documentation](https://solana.unity-sdk.gg/docs/jupiter) + +## Demos + +- Watch this demo video showcasing an in-game swap powered by the Jupiter integration: [Watch Demo Video](https://youtu.be/nCceV53thjY) +- Explore a live game demo here: [Live Demo](https://magicblock-labs.github.io/Solana.Unity-SDK/) \ No newline at end of file diff --git a/docs/2-development-basics.md b/docs/2-development-basics.md new file mode 100644 index 00000000..78b79400 --- /dev/null +++ b/docs/2-development-basics.md @@ -0,0 +1,112 @@ +--- +sidebar_label: "Development Basics" +description: "Under development basics on Solana to build with Jupiter API." +title: "Development Basics" +--- + + + Development Basics + + + +:::tip where is jupiter? +Jupiter is built on Solana MAINNET only! +::: + +Solana uses an account-based architecture where data are stored in accounts. However, Solana keeps Programs (also known as smart contracts on other blockchains) and Accounts distinct. In order to mutate the data in Accounts, you will need to send transactions to the network which execute Instructions defined by Programs. + +- [Programs](https://solana.com/docs/core/programs) on Solana are executable code deployed on-chain. They are designed to execute instructions, process transactions and interact with accounts. +- [Instructions](https://solana.com/docs/core/transactions#instruction) on Solana are defined by the Program, similar to API endpoints exposesd by a program. +- [Accounts](https://solana.com/docs/core/accounts) store data and are mutable, meaning they can be updated by the program who interacts with them. +- [Transactions](https://solana.com/docs/core/transactions#transaction) is what we send to interact with the network which can include one or more instructions to execute what is needed. + +## Interacting with Solana + +The Solana Web3.js and Rust client libraries serve as essential interfaces for interacting with Solana in JavaScript/TypeScript and Rust environments, respectively. They abstract complex interactions with the network, providing easier and more accessible functions for developers building on Solana. Here’s an overview of what each library offers and some of the most common functions they simplify: + +1. Connecting to the network via RPC (Remote Procedure Call) endpoints +2. Building Transactions +3. Interfacing with Solana Programs and Accounts + +:::note links +Explore the rich features and detailed documentation of these libraries in the official Solana Developer Documentation: [Web3.js](https://solana.com/docs/clients/javascript) and [Rust client](https://solana.com/docs/clients/rust) +::: + +## Interacting with Jupiter Programs + +To interact with the Jupiter Swap Aggregator Program, there are a few ways to do it: + +| Method | Description | +| --- | --- | +| Swap API | Simply call the Quote API to get a quote based on Jupiter’s routing engine and call the Swap API to get a serialized transaction to send to the network. | +| Flash Fill method | If you are building your own on-chain program, we recommend this method — an alternative method from CPI, using Versioned Transaction and Address Lookup Tables, thus reducing the size of each account (a limitation of using CPI method). | +| Cross Program Invocation (CPI) | https://solana.com/docs/core/cpi | + +## Building Transactions + +Before you send a transaction to the network, you will need to build the transaction that defines the instructions to execute and accounts to read/write to. It can be complex to handle this yourself when building with Jupiter, you can [read more about it here](https://solana.com/docs/core/transactions). + +However, good news! Most of our APIs and SDKs just handles it for you, so you get a response with the transaction to be prepared and sent to the network. + +:::tip swap api tip +The Swap API returns you the serialized transaction which you can directly send it to your RPC endpoint to execute on Solana. Alternatively, if you plan to manipulate the instructions and build your own custom transactions, you can request from the `/swap-instructions` endpoint. +::: + +## Sending Transactions + +Transactions on Solana can only be sent to the network through an RPC (Remote Procedure Call) endpoint. The Solana network operates with a client-server model where RPC nodes handle transactions and interact with the validators of the blockchain. We recommend using 3rd party RPC providers like [Triton](https://triton.one/) or [Helius](https://helius.dev/) for production applications. + +There are a few key points to note when sending transactions to the Solana network. At Jupiter, we do our best to help you optimize transaction sending and make it easier for you. + +1. Solana transaction base fee +2. Priority fee +3. Compute units +4. Transaction broadcasting methods +5. Slippage (100% slippage will always work but also mean you can possibly get the worst outcome, so we need to find the balance between success optimizations and best output price) + +## More about these factors? + +### What is Priority Fee? + +Transactions submitted to the blockchain are prioritized based on a fee-bidding process. The higher the priority fee, the higher your transaction will be placed in the execution queue. + +:::info Overpaying Priority Fee +It is important to note that overpaying for priority fee can be detrimental in the long run. If transactions continuously outbid each other, the overall fees required to process across the network will increase over time. +::: + +**Priority Fee** is an optional fee you can pay additionally to improve the chance of landing your transactions faster. + +- Priority Fee = **Compute Budget * Compute Unit Price** +- This is excluding the base transaction fee (5,000 lamports or 0.000005 SOL) that you always need to pay. +- You not only need to outbid other transactions trying to be included in the block, but also outbid those trying to write to the same account. + +| Terminologies | | +| --- | --- | +| Global Priority Fee | The Priority Fee estimation across the entire network. | +| Local Fee Market | The Priority Fee estimation when modifying a writable account (or hot account). | +| Priority Fee | Compute Budget * Compute Unit Price | +| Compute Budget | How much compute unit the transaction is supposed to consume | +| Compute Unit Price | Micro lamports per compute unit the transaction will use + +When querying the micro-lamport per compute unit for a particular program or account, it will contain both the Global and Local Fee markets. + +### What is Compute Unit? + +Compute Unit (CU) is a standardizded metric for evaluating how much "work" or "resource" is required by the transaction to execute. Different operations on Solana has varying amounts of CUs. In order to keep the blockchain efficient yet fast, each transaction, the Solana runtime has an absolute max compute unit limit of 1.4 million CU and sets a default requested max limit of 200k CU per instruction. + +:::tip Set custom Compute Unit Limit +A transaction can request a more specific and optimal compute unit limit by including a single `SetComputeUnitLimit` instruction. Either a higher or lower limit. But it may never request higher than the absolute max limit per transaction. +::: + +However, we must note that higher CU also means higher Priority Fee it might need to help prioritize it. + +### What are some transaction broadcasting methods? +1. Typical RPCs +2. RPCs with SWQoS +3. Jito RPC + +### What is Slippage? + +A percentage or bps threshold the user specify and if the actual executed output is less than quoted output by the percentage/bps, the transaction will fail. + +It is more like a safeguard but the tighter threshold you go, the harder it can become to land the transaction as markets can move rapidly. \ No newline at end of file diff --git a/docs/200-perp-api/1-perp-api.md b/docs/200-perp-api/1-perp-api.md new file mode 100644 index 00000000..62475b94 --- /dev/null +++ b/docs/200-perp-api/1-perp-api.md @@ -0,0 +1,14 @@ +--- +sidebar_label: "Perp API" +description: "Use the Jupiter Perp API to trade or analyze." +title: "Coming Soon!" +--- + + + Coming Soon! + + + +:::warning +The Perp API for trading and analyzing is still a **work in progress**, stay tuned! +::: \ No newline at end of file diff --git a/docs/200-perp-api/201-position-account.md b/docs/200-perp-api/201-position-account.md new file mode 100644 index 00000000..76794312 --- /dev/null +++ b/docs/200-perp-api/201-position-account.md @@ -0,0 +1,59 @@ +--- +sidebar_label: "Position Account" +description: "Understand and integrate the Jupiter Perp Program." +title: "Position Account" +--- + + + Position Account + + + +This page contains an overview of the **Solana account types** used in the Jupiter Perpetuals Program, and specifically the `Position` account. + +The `Position` account is a struct which represents a set of parameters and states associated to trade position data for a given token. + +:::note `Position` account derivation +The `Position` account's address is derived from the trader's wallet address / public key, the custody account, the collateral custody account, and a few other constant seeds. This means traders will always have the same Position account address for their open positions. + +This also means that traders only have nine positions available at one time: + +- Long SOL +- Long wETH +- Long wBTC +- Short SOL (USDC as collateral) +- Short SOL (USDT as collateral) +- Short wETH (USDC as collateral) +- Short wETH (USDT as collateral) +- Short wBTC (USDC as collateral) +- Short wBTC (USDT as collateral) + +This is an example [`Position` account](https://solscan.io/account/FBLzd5VM67MEKkoWerXu7Nu1ksbLXQvJDx63y5aeLEvt). +::: + +:::tip Example Typescript Repository +This [repository](https://github.com/julianfssen/jupiter-perps-anchor-idl-parsing) contains Typescript code samples on interacting with the Jupiter Perpetuals program IDL with `anchor` and `@solana/web3.js` + +You can also find the [Custody Account fields in the repository](https://github.com/julianfssen/jupiter-perps-anchor-idl-parsing/blob/1a0b5dc71081958895691047a9aa8ba51d2a8765/src/idl/jupiter-perpetuals-idl.ts#L2699) or on a [blockchain explorer](https://solscan.io/account/PERPHjGBqRHArX4DySjwM6UJHiR3sWAatqfdBS2qQJu#anchorProgramIdl). +::: + +## Account Details + +Each `Position` account contains the following data: + +| Field | Description | +| --- | --- | +| `owner` | **Type:** `publicKey`

The public key of the trader's account. | +| `pool` | **Type:** `publicKey`

The public key of the [JLP pool account](./pool-account). | +| `custody` | **Type:** `publicKey`

The public key of the position's [`custody` account](./custody-account). | +| `collateralCustody` | **Type:** `publicKey`

The public key of the position's collateral custody account.

Like the `custody` account, a `collateralCustody` account contains information for the token that's used as collateral for the position (SOL / wETH / wBTC for long positions, USDC / USDT for short positions). The borrow rates for the position will also be calculated based on the position's `collateralCustody`. | +| `openTime` | **Type:** `i64`

The open time of the position in UNIX timestamp format. | +| `updateTime` | **Type:** `i64`

The last updated time of the position in UNIX timestamp format. | +| `side` | **Type:** `Side`

The position's side, either `long` or `short`. | +| `price` | **Type:** `u64`

The entry price of the position when it was opened. The entry price is an integer in the atomic value (before decimals), a USDC (6 decimals) value of `158225872` is equivalent to $158.22. | +| `sizeUsd` | **Type:** `u64`

The position size after leverage in USD in the atomic value (before decimals). A position with `sizeUsd = 0` is treated as a closed position. | +| `collateralUsd` | **Type:** `u64`

The position's collateral size after fees in USD in the atomic value (before decimals). | +| `realisedPnlUsd` | **Type:** `i64`

The position's realized PNL when closing the position partially.

When a position is closed completely, the position's `realisedPnlUsd` will be `0` as the position is considered closed (as described in `sizeUsd`). | +| `cumulativeInterestSnapshot` | **Type:** `u128`

Stores the position's interest rate snapshot when it was last updated.

- The `collateralCustody` account for the respective collateral token stores a monotonically increasing counter in `collateralCustody .fundingRateState .cumulativeInterestRate`.

The difference between the `collateralCustody .fundingRateState .cumulativeInterestRate` and the position's `cumulativeInterestSnapshot` is used to calculate the borrow fees for the position. | +| `lockedAmount` | **Type:** `u64`

The amount of tokens (SOL / wETH / wBTC for long positions, USDC / USDT for short positions) locked to pay off the position's max potential profit. It acts as a cap on the maximum potential profit of the position. This amount is locked in the collateral custody to ensure the platform has sufficient tokens to pay out profitable trades. | +| `bump` | **Type:** `u8`

The bump seed used to derive the PDA for the `Position` account. | diff --git a/docs/200-perp-api/202-position-request-account.md b/docs/200-perp-api/202-position-request-account.md new file mode 100644 index 00000000..f1471722 --- /dev/null +++ b/docs/200-perp-api/202-position-request-account.md @@ -0,0 +1,70 @@ +--- +sidebar_label: "PositionRequest Account" +description: "Understand and integrate the Jupiter Perp Program." +title: "PositionRequest Account" +--- + + + PositionRequest Account + + + +This page contains an overview of the **Solana account types** used in the Jupiter Perpetuals Program, and specifically the `PositionRequest` account. + +The `PositionRequest` account is a struct which represents a set of parameters and states associated to a request to open or close a position, the `PositionRequest` account consists of mostly similar properties as [`Position` account](./position-account). + +:::note `PositionRequest` Account Derivation +It is a Program-Derived Address (PDA) derived from the underlying `Position` account's address, several constant seeds, and a random integer seed which makes each `PositionRequest` account unique. + +The is an example [`PositionRequest` account](https://solscan.io/account/DNnX2B1oiYqKLrbLLod1guuaZA28DQwJ8HuHsgDafoQK). +::: + +:::info `PositionRequestATA` account +A `PositionRequestATA` account is created for each `PositionRequest` account. + +The `PositionRequestATA` account is an [associated token account](https://spl.solana.com/associated-token-account) derived from the `PositionRequest` that contains the tokens from the trader's deposits or withdrawals from withdrawing collateral or closing positions. + +The tokens are then transferred to the position token's custody token account or returned to the trader's wallet when the `PositionRequestATA` account is closed. +::: + +:::info Take Profit / Stop Loss Requests +`PositionRequest` accounts for non TP / SL requests are closed as soon as the request is executed or rejected. + +TP / SL requests are also stored onchain via `PositionRequest` accounts. However, they will only be closed when the TP / SL request is triggered and executed. + +Active TP / SL requests can be fetched onchain (through blockchain explorers like Solscan or SolanaFM) by searching for the `PositionRequest` address or public key associated with the TP / SL request. +::: + +:::tip Example Typescript Repository +This [repository](https://github.com/julianfssen/jupiter-perps-anchor-idl-parsing) contains Typescript code samples on interacting with the Jupiter Perpetuals program IDL with `anchor` and `@solana/web3.js` + +You can also find the [Custody Account fields in the repository](https://github.com/julianfssen/jupiter-perps-anchor-idl-parsing/blob/1a0b5dc71081958895691047a9aa8ba51d2a8765/src/idl/jupiter-perpetuals-idl.ts#L2583) or on a [blockchain explorer](https://solscan.io/account/PERPHjGBqRHArX4DySjwM6UJHiR3sWAatqfdBS2qQJu#anchorProgramIdl). +::: + +## Account Details + +Each `PositionRequest` account contains the following data: + +| Field | Description | +| --- | --- | +| `owner` | **Type:** `publicKey`

The public key of the trader's account. | +| `pool` | **Type:** `publicKey`

The public key of the [JLP pool account](./pool-account). | +| `custody` | **Type:** `publicKey`

The public key of the position's [`custody` account](./custody-account). | +| `collateralCustody` | **Type:** `publicKey`

The public key of the position's collateral custody account.

Like the `custody` account, a `collateralCustody` account contains information for the token that's used as collateral for the position (SOL / wETH / wBTC for long positions, USDC / USDT for short positions). The borrow rates for the position will also be calculated based on the position's `collateralCustody`. | +| `mint` | **Type:** `publicKey`

For opening positions and collateral deposits, mint refers to the input mint requested by the trader.

For example, if a trader opens a position by providing the initial margin with SOL, then mint will be equal to SOL's mint address. If the trader deposits collateral in USDC, then mint will be equal to USDC's mint address.

For closing positions and collateral withdrawals, mint is equal the to position collateral token's mint address. For example, if a trader closes a long SOL position, mint will be equal to SOL's mint address. If a trader closes a short SOL position, mint is equal to USDC or USDT's mint address depending on the position's collateral. | +| `openTime` | **Type:** `i64`

The time when the request of position is created in UNIX timestamp format. | +| `updateTime` | **Type:** `i64`

The time when the request of position is last updated in UNIX timestamp format. | +| `sizeUsdDelta` | **Type:** `u64`

The USD amount to increase or decrease the position size by. The amount is an integer in the atomic value (before decimals which is 6 for USDC / UST mints).

For example, a position request to increase an open position's size by 10 USDC will have a `sizeUsdDelta = 10000000`. | +| `collateralDelta` | **Type:** `u64`

For opening positions and collateral deposits, `collateralDelta` is the token amount to increase or decrease the position collateral size by. The token amount is represented in atomic values (before decimals). | +| `requestChange` | **Type:** `RequestChange`

`requestChange` will be equal to `Increase` for open position and collateral deposit requests, and `Decrease` for close position and collateral withdrawal requests. | +| `requestType` | **Type:** `RequestType`

`Market` for all position requests except for TP / SL requests, which have a different `requestType` known as `Trigger`. | +| `side` | **Type:** `Side`

`Long` for long positions, `Short` for short positions | +| `priceSlippage` | **Type:** `u64`

The maximum price with slippage for position requests when opening, closing, or updating the position size.

- When increasing the size of a long position or decreasing the size of a short position, the request will fail if the current price of the position's token is greater than `priceSlippage`.

- When decreasing the size of a long position or increasing the size of a short position, the request will fail if `priceSlippage` is greater than the current price of the position's token. | +| `jupiterMinimumOut` | **Type:** `u64`

For requests that require token swaps, the output amount of the token swap must be greater than or equal to `jupiterMinimumOut`, else the request will fail. | +| `preSwapAmount` | **Type:** `u64`

This is an internal attribute used by the program to calculate the `collateralDelta` for position requests that require token swaps. | +| `triggerPrice` | **Type:** `u64`

The price (USD) used for TP / SL position requests. | +| `triggerAboveThreshold` | **Type:** `bool`

When `triggerAboveThreshold` is true, the TP / SL position request will be triggered when the position's token price is greater than or equal to `triggerPrice`. When `triggerAboveThreshold` is false, the TP / SL position request will be triggered when the position's token price is less than or equal to `triggerPrice`. | +| `entirePosition` | **Type:** `bool`

This attribute is only checked when closing or decreasing position sizes. When `entirePosition` is true, the entire position will be closed (i.e. a close position request). When `entirePosition` is false, the position size will be reduced according to sizeUsdDelta. | +| `executed` | **Type:** `bool`

Determines whether the position request is executed or not. | +| `counter` | **Type:** `u64`

The random integer seed used to derive the position request address. | +| `bump` | **Type:** `u8`

The bump seed used to derive the position request address. | diff --git a/docs/200-perp-api/203-pool-account.md b/docs/200-perp-api/203-pool-account.md new file mode 100644 index 00000000..b452938a --- /dev/null +++ b/docs/200-perp-api/203-pool-account.md @@ -0,0 +1,66 @@ +--- +sidebar_label: "Pool Account" +description: "Understand and integrate the Jupiter Perp Program." +title: "Pool Account" +--- + + + Pool Account + + + +This page contains an overview of the **Solana account types** used in the Jupiter Perpetuals Program, and specifically the `Pool` account. + +The `Pool` account is a struct which represents a set of parameters and states associated to the data for JLP pool, including AUM and [`Custody`](./custody-account) data. + +:::note only one pool account +There is only one [`Pool` account](https://solscan.io/account/5BUwFW4nRbftYTDMbgxykoFWqWHPzahFSNAaaaJtVKsq). +::: + +:::tip Example Typescript Repository +This [repository](https://github.com/julianfssen/jupiter-perps-anchor-idl-parsing) contains Typescript code samples on interacting with the Jupiter Perpetuals program IDL with `anchor` and `@solana/web3.js` + +You can also find the [Custody Account fields in the repository](https://github.com/julianfssen/jupiter-perps-anchor-idl-parsing/blob/1a0b5dc71081958895691047a9aa8ba51d2a8765/src/idl/jupiter-perpetuals-idl.ts#L2699) or on a [blockchain explorer](https://solscan.io/account/PERPHjGBqRHArX4DySjwM6UJHiR3sWAatqfdBS2qQJu#anchorProgramIdl). +::: + +## Account Details + +Each `Pool` account contains the following data: + +| Field | Description | +| --- | --- | +| `name` | **Type:** `string`

The name for the account. | +| `custodies` | **Type:** `publicKey`

An array containing the public keys for the custodies (tokens) managed by the JLP pool. | +| `aumUsd` | **Type:** `u128`

The current AUM value (USD) for the JLP pool. The `aumUsd` value's calculation can be summarized by getting the USD value of the tokens managed by the pool minus the USD value reserved to pay off trader profits.

Refer to the [Custody account](./custody-account) details for more details on AUM calculation. | +| `limit` | **Type:** [`Limit`](#limit)

Contains values for the pool's limits. | +| `fees` | **Type:** [`Fees`](#fees)

Sets the fee amounts or percentages for the Jupiter Perpetuals exchange. | +| `poolApr` | **Type:** [`PoolApr`](#poolapr)

Contains data related to the pool's APR / APY calculations. | + +### `Limit` + +| Field | Description | +| --- | --- | +| `maxAumUsd` | **Type:** `u128`

The max AUM for the JLP pool. This acts as a max cap / ceiling as the JLP will not accept deposits when the cap is hit. | +| `tokenWeightageBufferBps` | **Type:** `u128`

The token weightage buffer (in basis points) to calculate the token's maximum or minimum current weightage based on the target weightage.

Currently, `tokenWeightageBufferBps` is set to `2000` which means the the current weightage cannot be lower or higher than + / - 20% of the token's target weightage.

For example, if SOL's target weightage for the JLP pool is 50%, the current weightage cannot be less than 40% or exceed 60%. The pool will not allow deposits or withdrawals if the action causes the token to exceed its target weightage. | +| `maxPositionUsd` | **Type:** `u64`

Sets the maximum position size. The current `maxPositionUsd` value is `2_500_000_000_000` which means a position's max size is $2,500,000. | + +### `Fees` + +| Field | Description | +| --- | --- | +| `increasePositionBps` | **Type:** `string`

A fixed fee of 6 BPS (0.06%) is charged for opening or increasing a position. | +| `decreasePositionBps` | **Type:** `publicKey`

A fixed fee of 6 BPS (0.06%) is charged for closing or decreasing a position. | +| `addRemoveLiquidityBps` | **Type:** `u128`

Fee charged when adding or removing liquidity to/from the pool. | +| `swapBps` | **Type:** `Limit`

Swap fee for exchanging non-stablecoin tokens routed through the liquidity pool.

`swap fee = swapBps ± swapTaxBps` | +| `taxBps` | **Type:** `PoolApr`

Tax fee for non-stablecoins, determined based on the difference between the current and target weightage. A larger difference results in a higher tax fee, encouraging liquidity providers to rebalance the pool to the target weightage. | +| `stableSwapBps` | **Type:** `Limit`

Swap fee for exchanges involving stablecoins, routed through the liquidity pool.

`swap fee = stableSwapBps ± stableSwapTaxBps` | +| `stableSwapTaxBps` | **Type:** `Fees`

Tax fee for stablecoin swaps. Similar to taxBps, this fee is determined by the difference between the current and target weightage. | +| `protocolShareBps` | **Type:** `PoolApr`

Jupiter takes a share of 2500 BPS (25%) from the fees collected by the pool. | + +### `PoolApr` + +| Field | Description | +| --- | --- | +| `lastUpdated` | **Type:** `i64`

The UNIX timestamp when the pool's APR data was last updated. | +| `feeAprBps` | **Type:** `u64`

The pool's APR in BPS format. The APR is calculated weekly by dividing the pool's realized fees (minus the 25% collected by the protocol) by the total pool value, adjusting for the 1 week time period to annualize the rate. | +| `realizedFeeUsd` | **Type:** `u64`

The fees collected by the pool so far. This fee is reinvested back into the pool and is also used to calculate the APR as mentioned above. realizedFeeUsd resets to zero when the fee is reinvested into the pool hence causing the APR value to fluctuate weekly. | diff --git a/docs/200-perp-api/204-custody-account.md b/docs/200-perp-api/204-custody-account.md new file mode 100644 index 00000000..fc2f1360 --- /dev/null +++ b/docs/200-perp-api/204-custody-account.md @@ -0,0 +1,79 @@ +--- +sidebar_label: "Custody Account" +description: "Understand and integrate the Jupiter Perp Program." +title: "Custody Account" +--- + + + Custody Account + + + +This page contains an overview of the **Solana account types** used in the Jupiter Perpetuals Program, and specifically the `Custody` account. + +The `Custody` account is a struct which represents a set of parameters and states associated to custodies (tokens) managed by the JLP pool which consists of the following custodies. + + + + + + + + + + + + +
Custodies
SOLETHBTCUSDCUSDT
+ +:::tip Example Typescript Repository +This [repository](https://github.com/julianfssen/jupiter-perps-anchor-idl-parsing) contains Typescript code samples on interacting with the Jupiter Perpetuals program IDL with `anchor` and `@solana/web3.js` + +You can also find the [Custody Account fields in the repository](https://github.com/julianfssen/jupiter-perps-anchor-idl-parsing/blob/1a0b5dc71081958895691047a9aa8ba51d2a8765/src/idl/jupiter-perpetuals-idl.ts#L2397) or on a [blockchain explorer](https://solscan.io/account/PERPHjGBqRHArX4DySjwM6UJHiR3sWAatqfdBS2qQJu#anchorProgramIdl). +::: + +## Account Details + +Each `Custody` account contains the following data: + +| Field | Description | +| --- | --- | +| `pool` | **Type:** `publicKey`

The public key for the pool that this custody belongs to (i.e. the JLP pool). | +| `mint` | **Type:** `publicKey`

The public key for the custody's token mint account. | +| `tokenAccount` | **Type:** `publicKey`

The associated token account of the custody which holds the tokens under management for the pool. | +| `decimals` | **Type:** `u8`

The number of decimals used for the token which is the same as the number of decimals specified in the token mint account. This is stored for convenience. | +| `isStable` | **Type:** `bool`

A boolean flag indicating if the token in custody is a stable asset. | +| `oracle` | **Type:** `OracleParams`

Contains data for the price oracle used for the custody. | +| `pricing` | **Type:** [`PricingParams`](#pricingparams)

Contains data for the custody's price-related logic. | +| `permissions` | **Type:** `Permissions`

A set of global flags that can be set by the protocol's administrator to enable or disable trade actions which is useful during program upgrades or black swan events. | +| `targetRatioBps` | **Type:** `u64`

The target weightage (in basis points) for the custody in the JLP pool. | +| `assets` | **Type:** [`Assets`](#assets)

Contains data used to calculate PNL, AUM, and core business logic for the program. | +| `fundingRateState` | **Type:** [`FundingRateState`](#fundingratestate)

Contains data used to calculate borrow fees for open positions. | + +### `PricingParams` + +| Field | Description | +| --- | --- | +| `tradeImpactFeeScalar` | **Type:** `u64`

Sets the base value when calculating price impact fees when opening or closing positions. | +| `maxLeverage` | **Type:** `u64`

Sets the max leverage for this custody's positions. The max leverage for all custodies is 500x at the time of writing. | +| `maxGlobalLongSizes` | **Type:** `u64`

The maximum total position size (USD) for long positions. | +| `maxGlobalShortSizes` | **Type:** `u64`

The maximum total position size (USD) for short positions. | + +### `Assets` + +| Field | Description | +| --- | --- | +| `feesReserves` | **Type:** `u64`

The fees collected by all open positions for the custody. `feesReserves` resets to zero when the fees are distributed to the pool and protocol. | +| `owned` | **Type:** `u64`

The number of tokens owned by the pool for the custody.
- The owned value is increased either by providing liquidity to the pool or depositing collateral when opening or updating positions.
- Conversely, the owned value decreases when liquidity is removed from the pool or collateral is withdrawn from closing positions. | +| `locked` | **Type:** `u64`

The number of tokens locked by the pool for the custody to pay off potential profits for open positions. | +| `guaranteedUsd` | **Type:** `u64`

This value represents the total amount borrowed in USD (position size - collateral) across all long positions.

It is updated whenever traders modify their collateral through deposits or withdrawals. The system uses this aggregated figure to efficiently calculate the total profit and loss (PNL) for all long positions, which in turn is used to calculate the AUM of the JLP pool. | +| `globalShortSizes` | **Type:** `u64`

Stores the total amount (USD) position sizes for all short positions. | +| `globalShortAveragePrices` | **Type:** `u64`

Stores the average price (USD) for all short positions.

This value and `globalShortSizes` are used to calculate the PNL for all short positions efficiently, and is again used to calculate the AUM of the JLP pool. | + +### `FundingRateState` + +| Field | Description | +| --- | --- | +| `cumulativeInterestRate` | **Type:** `u128`

Traders are required to pay hourly borrow fees for opening leveraged positions. This fee is calculated based on two primary factors: the size of the trader's position and the current utilization of the pool for the custody.

To calculate borrow fees more efficiently, each custody account contains a value called `cumulativeInterestRate`.

Correspondingly, each position account stores a `cumulativeInterestSnapshot` which captures the value of `cumulativeInterestRate` at the time of the position's last update. Whenever there's a change in either the borrowed assets or the total assets within a custody, the `cumulativeInterestRate` for the custody is updated.

The difference between the custody's `cumulativeInterestRate` and the position's `cumulativeInterestSnapshot` is then used to calculate the position's borrow fees. | +| `lastUpdate` | **Type:** `i64`

The UNIX timestamp for when the custody's borrow fee data was last updated. | +| `hourlyFundingDbps` | **Type:** `u64`

A constant used to calculate the hourly borrow fees for the custody. The Jupiter Perpetuals exchange works with Gauntlet and Chaos Labs to update and fine tune the `hourlyFundingDbps` to respond to traders' feedback and market conditions. | diff --git a/docs/300-tool-kits/1-swap-terminal.md b/docs/300-tool-kits/1-swap-terminal.md new file mode 100644 index 00000000..f5b9c7da --- /dev/null +++ b/docs/300-tool-kits/1-swap-terminal.md @@ -0,0 +1,147 @@ +--- +sidebar_label: "Swap Terminal" +description: "An overview of Jupiter Swap Terminal and its core features." +title: "Swap Terminal" +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import Highlight from '@theme/CodeBlock'; + + + Swap Terminal + + + +Jupiter Terminal is an open-sourced, lite version of Jupiter. This terminal provides end-to-end swap functionality by linking it in your HTML with just a few lines of code. + +:::tip Jupiter Terminal References +- [Terminal Playground](https://terminal.jup.ag/): To play with different settings,features and styling. +- [Open Source Repository](https://github.com/jup-ag/terminal): To understand and make use of the Jupiter Terminal better. +- [API Type Reference](https://github.com/jup-ag/terminal/blob/main/src/types/index.d.ts): To utilize the different references. +::: + + + +## Core Features + +| **Feature** | **Details** | +|---|---| +| **Lightweight** | -`main-v3.js` bundle (~70KB gzippped)
- App bundle (~1.1 MB gzipped) loads on-demand when `init()` is called.
- Preload app bundle with `data-preload` attributes. | +| **Agnostic** | - Works with any application in Integrated, Widget, or Modal format.
- Compatible with frameworks like React, Plain HTML, etc.
- Responsive to all screen sizes. | +| **Customization** | - Supports Swap, Payment, or Ape tokens use cases.
- Allows fixed input/output amounts or mint.
- Offers ExactIn or ExactOut swap modes. | +| **Built-in Wallets** | - Wallet Standard support, powered by Unified Wallet Kit.
- Passthrough wallet from your app. | +| **Fees Support** | - Customizable fees and trackable via [Referral Dashboard](https://referral.jup.ag/dashboard). | + +## API References + +
+ + Typescript Support + +Since Jupiter Terminal is only importable via CDN, to get proper typing, you can create a typing declaration jupiter-terminal.d.ts file in your project, and copy the contents in src/types/index.d.ts. + +```jsx +declare global { + interface Window { + Jupiter: JupiterTerminal; + } +} +// ... +// ... +// ... +``` +
+ +
+ + Fee Support + +There are no protocol fees on Jupiter, but integrators can introduce a platform fee on through the Swap Terminal as underlying, it is using the Swap API which allows you to take fees. + +Refer to the [Add Fees To Swap](../100-swap-api/4-add-fees-to-swap.md) guide to get the accounts and add it. + +```jsx +window.Jupiter.init({ + // ... + platformFeeAndAccounts, +}); +``` +
+ +
+ + Resuming / Closing Activity + +- Every time `init()` is called, it will create a new activity. +- If you want to resume from previous activity, you can use `resume()` instead. +- `close()` function to hide the widget. + +```jsx +if (window.Jupiter._instance) { + window.Jupiter.resume(); +} + +window.Jupiter.close(); +``` +
+ +
+ + Token List + +The Jupiter Token List API is an open, collaborative and dynamic token list to make trading on Solana more transparent and safer for all. It is default to `true` to ensure that only validated tokens are shown. + +- `strictTokenList?: boolean;` + +
+ +
+ + onSuccess / onSwapError Callback + +`onSuccess()` and `onSwapError()` reference can be provided, when swap is successful or errored respectively. + +```jsx +window.Jupiter.init({ + onSuccess: ({ txid, swapResult }) => { + console.log({ txid, swapResult }); + }, + onSwapError: ({ error }) => { + console.log('onSwapError', error); + }, +}); +``` +
+ +
+ + Customizing Styles + + +**CSS Properties** + +Any CSS-in-JS can be injected to the outer-most container via `containerStyles` API. + +```jsx +window.Jupiter.init({ + // ... + containerStyles: { zIndex: 100 }, + containerStyles: { maxHeight: '90vh' }, +}); +``` + +**className (Tailwind)** + +Tailwind classes can be injected to the outer-most container via `containerClassName` API. + +```jsx +window.Jupiter.init({ + // ... + containerClassName: 'max-h-[90vh] lg:max-h-[600px]', +}); +``` +
diff --git a/docs/300-tool-kits/2-terminal-walkthrough.md b/docs/300-tool-kits/2-terminal-walkthrough.md new file mode 100644 index 00000000..989ff0fc --- /dev/null +++ b/docs/300-tool-kits/2-terminal-walkthrough.md @@ -0,0 +1,135 @@ +--- +sidebar_label: "Terminal Walkthrough" +description: "Step by step walkthrough of integrating Jupiter Swap Terminal into your website with minimal code." +title: "Terminal Walkthrough" +--- + + + Terminal Walkthrough + + + +In this step by step walkthrough, we will utilize the Solana Dapp Scaffold codebase to demonstrate integrating Jupiter Swap Terminal! + +You can also [watch the tutorial on YouTube](https://youtu.be/T-3KN3k1e5Y)! + + + + +## Let's Get Started + +Since we are building on top of the Solana Dapp Scaffold, we'll start by setting up the necessary codebase and dependencies. + +:::tip Jupiter Terminal References +- [Terminal Playground](https://terminal.jup.ag/): To play with different settings,features and styling. +- [Open Source Repository](https://github.com/jup-ag/terminal): To understand and make use of the Jupiter Terminal better. +- [API Type Reference](https://github.com/jup-ag/terminal/blob/main/src/types/index.d.ts): To utilize the different references. +::: + +## Set up + +Clone the repository to local machine or working environment. +```bash +git clone https://github.com/solana-labs/dapp-scaffold.git +``` + +Install the dependencies. +```bash +pnpm install +``` + +Load the site in your localhost. +```bash +pnpm dev +``` + +## Modify files + +### Change network configuration + +Next, navigate to `dapp-scaffold/src/contexts/NetworkConfigurationProvider.tsx` file and change your network configuration from `devnet` to `mainnet-beta`. + +```jsx +const [networkConfiguration, setNetworkConfiguration] = useLocalStorage("network", "mainnet-beta"); +``` + +### Add Jupiter Terminal script + +In the `dapp-scaffold/src/pagers/_document.tsx` file, include your Jupiter Terminal script. + +```jsx +... + + + +