diff --git a/.gitignore b/.gitignore index 061ef89..8b319ff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,179 @@ venv/ __pycache__/ -main.py \ No newline at end of file +main.py + +# Compiler files +cache/ +out/ + +# Ignores development broadcast logs +!/broadcast +/broadcast/*/31337/ +/broadcast/**/dry-run/ + +# Docs +docs/ + +# Dotenv file +.env + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE similarity index 100% rename from LICENSE.txt rename to LICENSE diff --git a/README.md b/README.md index b9390fb..d2eaec0 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ **Jupiter Python SDK** is a Python library that allows you to use most of **[Jupiter](https://jup.ag/) features**.
It enables executing swaps, limit orders, DCA, swap pairs, tokens prices, fetching wallet infos, stats, data and more!
This library is using packages like: [solana-py](https://github.com/michaelhly/solana-py), [solders](https://github.com/kevinheavey/solders), [anchorpy](https://github.com/kevinheavey/anchorpy).
-There is documentation inside each function, however, you can access to the [official Jupiter API](https://docs.jup.ag/docs). +There is documentation inside each function, however, you can access to the [official Jupiter API](https://docs.jup.ag/docs) for more information. # ⚠️ Disclaimer **Please note that I'm not responsible for any loss of funds, damages, or other libailities resulting from the use of this software or any associated services.
@@ -34,58 +34,115 @@ This tool is provided for educational purposes only and should not be used as fi ```sh pip install jupiter-python-sdk ``` + ### 📃 General Usage **Providing the private key and RPC client is not mandatory if you only intend to execute functions for retrieving data.
Otherwise, this is required, for instance, to open a DCA account or to close one.** + +**You can set custom URLs for any self-hosted Jupiter APIs. Like the [V6 Swap API](https://station.jup.ag/docs/apis/self-hosted) or [QuickNode's Metis API](https://marketplace.quicknode.com/add-on/metis-jupiter-v6-swap-api).** + +If you encounter ```ImportError: cannot import name 'sync_native' from 'spl.token.instructions``` error when trying to import Jupiter, Jupiter_DCA from jupiter_python_sdk.jupiter, follow these steps: +1. Go to https://github.com/michaelhly/solana-py/tree/master/src/spl/token and download ```instructions.py``` +2. In your packages folder, replace ```spl/token/instructions.py``` with the one you just downloaded. + +### Here is a code snippet on how to use the SDK ```py import base58 +import base64 +import json + +from solders import message from solders.pubkey import Pubkey from solders.keypair import Keypair +from solders.transaction import VersionedTransaction + +from solana.rpc.types import TxOpts from solana.rpc.async_api import AsyncClient +from solana.rpc.commitment import Processed + from jupiter_python_sdk.jupiter import Jupiter, Jupiter_DCA -async def main(): - private_key = Keypair.from_bytes(base58.b58decode(os.getenv("PRIVATE_KEY"))) # Private key as string - async_client = AsyncClient(os.getenv("RPC_API")) - jupiter = Jupiter(async_client, private_key) - - # EXECUTE A SWAP - swap = await jupiter.swap( - input_mint=Pubkey.from_string("So11111111111111111111111111111111111111112"), - output_mint=Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), - amount=5_000_000, - slippage_bps=1, - ) - # Returns str: serialized transactions to execute the swap. - - # OPEN LIMIT ORDER - open_limit_order = await jupiter.open_order( - input_mint=Pubkey.from_string("So11111111111111111111111111111111111111112"), - output_mint=Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), - in_amount=5_000_000, - out_amount=100_000, - ) - # Returns dict: {'transaction_data': serialized transactions to create the limit order, 'signature2': signature of the account that will be opened} - - # CREATE DCA ACCOUNT - create_dca_account = await jupiter.dca.create_dca( - input_mint=Pubkey.from_string("So11111111111111111111111111111111111111112"), - output_mint=Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), - total_in_amount=5_000_000, - in_amount_per_cycle=100_000, - cycle_frequency=60, - min_out_amount_per_cycle=0, - max_out_amount_per_cycle=0, - start=0 - ) - # Returns DCA Account Pubkey and transaction hash. - - # CLOSE DCA ACCOUNT - close_dca_account = await jupiter.dca.close_dca( - dca_pubkey=Pubkey.from_string("45iYdjmFUHSJCQHnNpWNFF9AjvzRcsQUP9FDBvJCiNS1") - ) - # Returns transaction hash. + +private_key = Keypair.from_bytes(base58.b58decode(os.getenv("PRIVATE-KEY"))) # Replace PRIVATE-KEY with your private key as string +async_client = AsyncClient("SOLANA-RPC-ENDPOINT-URL") # Replace SOLANA-RPC-ENDPOINT-URL with your Solana RPC Endpoint URL +jupiter = Jupiter( + async_client=async_client, + keypair=private_key, + quote_api_url="https://quote-api.jup.ag/v6/quote?", + swap_api_url="https://quote-api.jup.ag/v6/swap", + open_order_api_url="https://jup.ag/api/limit/v1/createOrder", + cancel_orders_api_url="https://jup.ag/api/limit/v1/cancelOrders", + query_open_orders_api_url="https://jup.ag/api/limit/v1/openOrders?wallet=", + query_order_history_api_url="https://jup.ag/api/limit/v1/orderHistory", + query_trade_history_api_url="https://jup.ag/api/limit/v1/tradeHistory" +) + + +""" +EXECUTE A SWAP +""" +transaction_data = await jupiter.swap( + input_mint="So11111111111111111111111111111111111111112", + output_mint="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + amount=5_000_000, + slippage_bps=1, +) +# Returns str: serialized transactions to execute the swap. + +raw_transaction = VersionedTransaction.from_bytes(base64.b64decode(transaction_data)) +signature = private_key.sign_message(message.to_bytes_versioned(raw_transaction.message)) +signed_txn = VersionedTransaction.populate(raw_transaction.message, [signature]) +opts = TxOpts(skip_preflight=False, preflight_commitment=Processed) +result = await async_client.send_raw_transaction(txn=bytes(signed_txn), opts=opts) +transaction_id = json.loads(result.to_json())['result'] +print(f"Transaction sent: https://explorer.solana.com/tx/{transaction_id}") + + +""" +OPEN LIMIT ORDER +""" +transaction_data = await jupiter.open_order( + input_mint=So11111111111111111111111111111111111111112", + output_mint=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + in_amount=5_000_000, + out_amount=100_000, +) +# Returns dict: {'transaction_data': serialized transactions to create the limit order, 'signature2': signature of the account that will be opened} + +raw_transaction = VersionedTransaction.from_bytes(base64.b64decode(transaction_data['transaction_data'])) +signature = private_key.sign_message(message.to_bytes_versioned(raw_transaction.message)) +signed_txn = VersionedTransaction.populate(raw_transaction.message, [signature, transaction_data['signature2']]) +opts = TxOpts(skip_preflight=False, preflight_commitment=Processed) +result = await async_client.send_raw_transaction(txn=bytes(signed_txn), opts=opts) +transaction_id = json.loads(result.to_json())['result'] +print(f"Transaction sent: https://explorer.solana.com/tx/{transaction_id}") + + +""" +CREATE DCA ACCOUNT +""" +create_dca_account = await jupiter.dca.create_dca( + input_mint=Pubkey.from_string("So11111111111111111111111111111111111111112"), + output_mint=Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), + total_in_amount=5_000_000, + in_amount_per_cycle=100_000, + cycle_frequency=60, + min_out_amount_per_cycle=0, + max_out_amount_per_cycle=0, + start=0 +) +# Returns DCA Account Pubkey and transaction hash. + + +""" +CLOSE DCA ACCOUNT +""" +close_dca_account = await jupiter.dca.close_dca( + dca_pubkey=Pubkey.from_string("45iYdjmFUHSJCQHnNpWNFF9AjvzRcsQUP9FDBvJCiNS1") +) +# Returns transaction hash. ``` + ### 📜 All available features ```py - quote @@ -115,11 +172,13 @@ async def main(): # 📝 TO-DO - [ ] Bridge 🌉 - [ ] Perpetual 💸 +- [ ] Price API +- [ ] Wallet Transactions History # 🤝 Contributions If you are interesting in contributing, fork the repository and submit a pull request in order to merge your improvements into the main repository.
Contact me for any inquiry, I will reach you as soon as possible.
-[![Discord](https://img.shields.io/badge/Discord-%237289DA.svg?logo=discord&logoColor=white)](https://discord.gg/_taodev_) +[![Discord](https://img.shields.io/badge/Discord-%237289DA.svg?logo=discord&logoColor=white)](https://discord.gg/QxwPGcXDp7) [![Twitter](https://img.shields.io/badge/Twitter-%231DA1F2.svg?logo=Twitter&logoColor=white)](https://twitter.com/_TaoDev_) # 👑 Donations diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..9c91e35 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +base58 +solders==0.18.1 +solana==0.30.2 +httpx +anchorpy==0.18.0 +jupiter-python-sdk diff --git a/src/jupiter_python_sdk/LICENSE.txt b/src/LICENSE.txt similarity index 100% rename from src/jupiter_python_sdk/LICENSE.txt rename to src/LICENSE.txt diff --git a/src/README.md b/src/README.md new file mode 100644 index 0000000..c29cce5 --- /dev/null +++ b/src/README.md @@ -0,0 +1,187 @@ +
+

🐍 JUPITER PYTHON SDK 🪐

+ +
+ +--- + +

+ + +
+ + +
+ + +
+

+ +# 📖 Introduction +**Jupiter Python SDK** is a Python library that allows you to use most of **[Jupiter](https://jup.ag/) features**.
+It enables executing swaps, limit orders, DCA, swap pairs, tokens prices, fetching wallet infos, stats, data and more!
+This library is using packages like: [solana-py](https://github.com/michaelhly/solana-py), [solders](https://github.com/kevinheavey/solders), [anchorpy](https://github.com/kevinheavey/anchorpy).
+There is documentation inside each function, however, you can access to the [official Jupiter API](https://docs.jup.ag/docs) for more information. + +# ⚠️ Disclaimer +**Please note that I'm not responsible for any loss of funds, damages, or other libailities resulting from the use of this software or any associated services.
+This tool is provided for educational purposes only and should not be used as financial advice, it is still in expiremental phase so use it at your own risk.** + +# ✨ Quickstart + +### 🛠️ Installation + +```sh +pip install jupiter-python-sdk +``` + +### 📃 General Usage +**Providing the private key and RPC client is not mandatory if you only intend to execute functions for retrieving data.
+Otherwise, this is required, for instance, to open a DCA account or to close one.** + +**You can set custom URLs for any self-hosted Jupiter APIs. Like the [V6 Swap API](https://station.jup.ag/docs/apis/self-hosted) or [QuickNode's Metis API](https://marketplace.quicknode.com/add-on/metis-jupiter-v6-swap-api).** + +If you encounter ```ImportError: cannot import name 'sync_native' from 'spl.token.instructions``` error when trying to import Jupiter, Jupiter_DCA from jupiter_python_sdk.jupiter, follow these steps: +1. Go to https://github.com/michaelhly/solana-py/tree/master/src/spl/token and download ```instructions.py``` +2. In your packages folder, replace ```spl/token/instructions.py``` with the one you just downloaded. + +### Here is a code snippet on how to use the SDK +```py +import base58 +import base64 +import json + +from solders import message +from solders.pubkey import Pubkey +from solders.keypair import Keypair +from solders.transaction import VersionedTransaction + +from solana.rpc.types import TxOpts +from solana.rpc.async_api import AsyncClient +from solana.rpc.commitment import Processed + +from jupiter_python_sdk.jupiter import Jupiter, Jupiter_DCA + + +private_key = Keypair.from_bytes(base58.b58decode(os.getenv("PRIVATE-KEY"))) # Replace PRIVATE-KEY with your private key as string +async_client = AsyncClient("SOLANA-RPC-ENDPOINT-URL") # Replace SOLANA-RPC-ENDPOINT-URL with your Solana RPC Endpoint URL +jupiter = Jupiter( + async_client=async_client, + keypair=private_key, + quote_api_url="https://quote-api.jup.ag/v6/quote?", + swap_api_url="https://quote-api.jup.ag/v6/swap", + open_order_api_url="https://jup.ag/api/limit/v1/createOrder", + cancel_orders_api_url="https://jup.ag/api/limit/v1/cancelOrders", + query_open_orders_api_url="https://jup.ag/api/limit/v1/openOrders?wallet=", + query_order_history_api_url="https://jup.ag/api/limit/v1/orderHistory", + query_trade_history_api_url="https://jup.ag/api/limit/v1/tradeHistory" +) + + +""" +EXECUTE A SWAP +""" +transaction_data = await jupiter.swap( + input_mint="So11111111111111111111111111111111111111112", + output_mint="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + amount=5_000_000, + slippage_bps=1, +) +# Returns str: serialized transactions to execute the swap. + +raw_transaction = VersionedTransaction.from_bytes(base64.b64decode(transaction_data)) +signature = private_key.sign_message(message.to_bytes_versioned(raw_transaction.message)) +signed_txn = VersionedTransaction.populate(raw_transaction.message, [signature]) +opts = TxOpts(skip_preflight=False, preflight_commitment=Processed) +result = await async_client.send_raw_transaction(txn=bytes(signed_txn), opts=opts) +transaction_id = json.loads(result.to_json())['result'] +print(f"Transaction sent: https://explorer.solana.com/tx/{transaction_id}") + + +""" +OPEN LIMIT ORDER +""" +transaction_data = await jupiter.open_order( + input_mint=So11111111111111111111111111111111111111112", + output_mint=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + in_amount=5_000_000, + out_amount=100_000, +) +# Returns dict: {'transaction_data': serialized transactions to create the limit order, 'signature2': signature of the account that will be opened} + +raw_transaction = VersionedTransaction.from_bytes(base64.b64decode(transaction_data['transaction_data'])) +signature = private_key.sign_message(message.to_bytes_versioned(raw_transaction.message)) +signed_txn = VersionedTransaction.populate(raw_transaction.message, [signature, transaction_data['signature2']]) +opts = TxOpts(skip_preflight=False, preflight_commitment=Processed) +result = await async_client.send_raw_transaction(txn=bytes(signed_txn), opts=opts) +transaction_id = json.loads(result.to_json())['result'] +print(f"Transaction sent: https://explorer.solana.com/tx/{transaction_id}") + + +""" +CREATE DCA ACCOUNT +""" +create_dca_account = await jupiter.dca.create_dca( + input_mint=Pubkey.from_string("So11111111111111111111111111111111111111112"), + output_mint=Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), + total_in_amount=5_000_000, + in_amount_per_cycle=100_000, + cycle_frequency=60, + min_out_amount_per_cycle=0, + max_out_amount_per_cycle=0, + start=0 +) +# Returns DCA Account Pubkey and transaction hash. + + +""" +CLOSE DCA ACCOUNT +""" +close_dca_account = await jupiter.dca.close_dca( + dca_pubkey=Pubkey.from_string("45iYdjmFUHSJCQHnNpWNFF9AjvzRcsQUP9FDBvJCiNS1") +) +# Returns transaction hash. +``` + +### 📜 All available features +```py +- quote +- swap +- open_order +- cancel_orders +- create_dca +- close_dca +- fetch_user_dca_accounts +- fetch_dca_account_fills_history +- get_available_dca_tokens +- fetch_dca_data +- query_open_orders +- query_orders_history +- query_trades_history +- get_jupiter_stats +- get_token_price +- get_indexed_route_map +- get_tokens_list +- get_all_tickers +- get_all_swap_pairs +- get_swap_pairs +- get_token_stats_by_date +- program_id_to_label +``` + +# 📝 TO-DO +- [ ] Bridge 🌉 +- [ ] Perpetual 💸 + +# 🤝 Contributions +If you are interesting in contributing, fork the repository and submit a pull request in order to merge your improvements into the main repository.
+Contact me for any inquiry, I will reach you as soon as possible.
+[![Discord](https://img.shields.io/badge/Discord-%237289DA.svg?logo=discord&logoColor=white)](https://discord.gg/QxwPGcXDp7) +[![Twitter](https://img.shields.io/badge/Twitter-%231DA1F2.svg?logo=Twitter&logoColor=white)](https://twitter.com/_TaoDev_) + +# 👑 Donations +This project doesn't include platform fees. If you find value in it and would like to support its development, your donations are greatly appreciated.
+**SOLANA ADDRESS** +```sh +AyWu89SjZBW1MzkxiREmgtyMKxSkS1zVy8Uo23RyLphX +``` diff --git a/src/build/lib/jupiter_python_sdk/__init__.py b/src/build/lib/jupiter_python_sdk/__init__.py deleted file mode 100644 index f987a05..0000000 --- a/src/build/lib/jupiter_python_sdk/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Classes to use Jupiter features.""" diff --git a/src/build/lib/jupiter_python_sdk/jupiter.py b/src/build/lib/jupiter_python_sdk/jupiter.py deleted file mode 100644 index 207fd54..0000000 --- a/src/build/lib/jupiter_python_sdk/jupiter.py +++ /dev/null @@ -1,1122 +0,0 @@ -import base64 -import json -import time -import struct - -import httpx -from httpx._config import Timeout - -from typing import Any - -from solders import message -from solders.pubkey import Pubkey -from solders.keypair import Keypair -from solders.transaction import VersionedTransaction -from solders.system_program import transfer, TransferParams - -from solana.rpc.types import TxOpts -from solana.rpc.async_api import AsyncClient -from solana.rpc.commitment import Processed - -from spl.token.instructions import create_associated_token_account, get_associated_token_address, sync_native, SyncNativeParams, close_account, CloseAccountParams -from spl.token.constants import * - -from construct import Container -from anchorpy.program.core import Program as AnchorProgram -from anchorpy.program.core import Idl, Provider -from anchorpy.provider import Wallet -from anchorpy import Context -from anchorpy import AccountsCoder - - -class Jupiter_DCA(): - - DCA_PROGRAM_ID = Pubkey.from_string("DCA265Vj8a9CEuX1eb1LWRnDT7uK6q1xMipnNyatn23M") - IDL = {"version":"0.1.0","name":"dca","instructions":[{"name":"openDca","accounts":[{"name":"dca","isMut":True,"isSigner":False},{"name":"user","isMut":True,"isSigner":True},{"name":"inputMint","isMut":False,"isSigner":False},{"name":"outputMint","isMut":False,"isSigner":False},{"name":"userAta","isMut":True,"isSigner":False},{"name":"inAta","isMut":True,"isSigner":False},{"name":"outAta","isMut":True,"isSigner":False},{"name":"systemProgram","isMut":False,"isSigner":False},{"name":"tokenProgram","isMut":False,"isSigner":False},{"name":"associatedTokenProgram","isMut":False,"isSigner":False},{"name":"eventAuthority","isMut":False,"isSigner":False},{"name":"program","isMut":False,"isSigner":False}],"args":[{"name":"applicationIdx","type":"u64"},{"name":"inAmount","type":"u64"},{"name":"inAmountPerCycle","type":"u64"},{"name":"cycleFrequency","type":"i64"},{"name":"minPrice","type":{"option":"u64"}},{"name":"maxPrice","type":{"option":"u64"}},{"name":"startAt","type":{"option":"i64"}},{"name":"closeWsolInAta","type":{"option":"bool"}}]},{"name":"openDcaV2","accounts":[{"name":"dca","isMut":True,"isSigner":False},{"name":"user","isMut":False,"isSigner":True},{"name":"payer","isMut":True,"isSigner":True},{"name":"inputMint","isMut":False,"isSigner":False},{"name":"outputMint","isMut":False,"isSigner":False},{"name":"userAta","isMut":True,"isSigner":False},{"name":"inAta","isMut":True,"isSigner":False},{"name":"outAta","isMut":True,"isSigner":False},{"name":"systemProgram","isMut":False,"isSigner":False},{"name":"tokenProgram","isMut":False,"isSigner":False},{"name":"associatedTokenProgram","isMut":False,"isSigner":False},{"name":"eventAuthority","isMut":False,"isSigner":False},{"name":"program","isMut":False,"isSigner":False}],"args":[{"name":"applicationIdx","type":"u64"},{"name":"inAmount","type":"u64"},{"name":"inAmountPerCycle","type":"u64"},{"name":"cycleFrequency","type":"i64"},{"name":"minPrice","type":{"option":"u64"}},{"name":"maxPrice","type":{"option":"u64"}},{"name":"startAt","type":{"option":"i64"}}]},{"name":"closeDca","accounts":[{"name":"user","isMut":True,"isSigner":True},{"name":"dca","isMut":True,"isSigner":False},{"name":"inputMint","isMut":False,"isSigner":False},{"name":"outputMint","isMut":False,"isSigner":False},{"name":"inAta","isMut":True,"isSigner":False},{"name":"outAta","isMut":True,"isSigner":False},{"name":"userInAta","isMut":True,"isSigner":False},{"name":"userOutAta","isMut":True,"isSigner":False},{"name":"systemProgram","isMut":False,"isSigner":False},{"name":"tokenProgram","isMut":False,"isSigner":False},{"name":"associatedTokenProgram","isMut":False,"isSigner":False},{"name":"eventAuthority","isMut":False,"isSigner":False},{"name":"program","isMut":False,"isSigner":False}],"args":[]},{"name":"withdraw","accounts":[{"name":"user","isMut":True,"isSigner":True},{"name":"dca","isMut":True,"isSigner":False},{"name":"inputMint","isMut":False,"isSigner":False},{"name":"outputMint","isMut":False,"isSigner":False},{"name":"dcaAta","isMut":True,"isSigner":False},{"name":"userInAta","isMut":True,"isSigner":False,"isOptional":True},{"name":"userOutAta","isMut":True,"isSigner":False,"isOptional":True},{"name":"systemProgram","isMut":False,"isSigner":False},{"name":"tokenProgram","isMut":False,"isSigner":False},{"name":"associatedTokenProgram","isMut":False,"isSigner":False},{"name":"eventAuthority","isMut":False,"isSigner":False},{"name":"program","isMut":False,"isSigner":False}],"args":[{"name":"withdrawParams","type":{"defined":"WithdrawParams"}}]},{"name":"deposit","accounts":[{"name":"user","isMut":True,"isSigner":True},{"name":"dca","isMut":True,"isSigner":False},{"name":"inAta","isMut":True,"isSigner":False},{"name":"userInAta","isMut":True,"isSigner":False},{"name":"tokenProgram","isMut":False,"isSigner":False},{"name":"eventAuthority","isMut":False,"isSigner":False},{"name":"program","isMut":False,"isSigner":False}],"args":[{"name":"depositIn","type":"u64"}]},{"name":"withdrawFees","accounts":[{"name":"admin","isMut":True,"isSigner":True},{"name":"mint","isMut":False,"isSigner":False},{"name":"feeAuthority","isMut":False,"isSigner":False,"docs":["CHECK"]},{"name":"programFeeAta","isMut":True,"isSigner":False},{"name":"adminFeeAta","isMut":True,"isSigner":False},{"name":"systemProgram","isMut":False,"isSigner":False},{"name":"tokenProgram","isMut":False,"isSigner":False},{"name":"associatedTokenProgram","isMut":False,"isSigner":False}],"args":[{"name":"amount","type":"u64"}]},{"name":"initiateFlashFill","accounts":[{"name":"keeper","isMut":True,"isSigner":True},{"name":"dca","isMut":True,"isSigner":False},{"name":"inputMint","isMut":False,"isSigner":False,"docs":["The token to borrow"]},{"name":"keeperInAta","isMut":True,"isSigner":False,"docs":["The account to send borrowed tokens to"]},{"name":"inAta","isMut":True,"isSigner":False,"docs":["The account to borrow from"]},{"name":"outAta","isMut":False,"isSigner":False,"docs":["The account to repay to"]},{"name":"instructionsSysvar","isMut":False,"isSigner":False,"docs":["Solana Instructions Sysvar"]},{"name":"systemProgram","isMut":False,"isSigner":False},{"name":"tokenProgram","isMut":False,"isSigner":False},{"name":"associatedTokenProgram","isMut":False,"isSigner":False}],"args":[]},{"name":"fulfillFlashFill","accounts":[{"name":"keeper","isMut":True,"isSigner":True},{"name":"dca","isMut":True,"isSigner":False},{"name":"inputMint","isMut":False,"isSigner":False},{"name":"outputMint","isMut":False,"isSigner":False},{"name":"keeperInAta","isMut":False,"isSigner":False},{"name":"inAta","isMut":False,"isSigner":False},{"name":"outAta","isMut":False,"isSigner":False},{"name":"feeAuthority","isMut":False,"isSigner":False,"docs":["CHECK"]},{"name":"feeAta","isMut":True,"isSigner":False},{"name":"instructionsSysvar","isMut":False,"isSigner":False,"docs":["Solana Instructions Sysvar"]},{"name":"systemProgram","isMut":False,"isSigner":False},{"name":"tokenProgram","isMut":False,"isSigner":False},{"name":"associatedTokenProgram","isMut":False,"isSigner":False},{"name":"eventAuthority","isMut":False,"isSigner":False},{"name":"program","isMut":False,"isSigner":False}],"args":[{"name":"repayAmount","type":"u64"}]},{"name":"transfer","accounts":[{"name":"keeper","isMut":True,"isSigner":True},{"name":"dca","isMut":True,"isSigner":False},{"name":"user","isMut":True,"isSigner":False},{"name":"outputMint","isMut":False,"isSigner":False},{"name":"dcaOutAta","isMut":True,"isSigner":False},{"name":"userOutAta","isMut":True,"isSigner":False,"isOptional":True},{"name":"intermediateAccount","isMut":True,"isSigner":False,"isOptional":True},{"name":"systemProgram","isMut":False,"isSigner":False},{"name":"tokenProgram","isMut":False,"isSigner":False},{"name":"associatedTokenProgram","isMut":False,"isSigner":False},{"name":"eventAuthority","isMut":False,"isSigner":False},{"name":"program","isMut":False,"isSigner":False}],"args":[]},{"name":"endAndClose","accounts":[{"name":"keeper","isMut":True,"isSigner":True},{"name":"dca","isMut":True,"isSigner":False},{"name":"inputMint","isMut":False,"isSigner":False},{"name":"outputMint","isMut":False,"isSigner":False},{"name":"inAta","isMut":True,"isSigner":False},{"name":"outAta","isMut":True,"isSigner":False},{"name":"user","isMut":True,"isSigner":False},{"name":"userOutAta","isMut":True,"isSigner":False,"isOptional":True},{"name":"initUserOutAta","isMut":True,"isSigner":False,"isOptional":True},{"name":"intermediateAccount","isMut":True,"isSigner":False,"isOptional":True},{"name":"systemProgram","isMut":False,"isSigner":False},{"name":"tokenProgram","isMut":False,"isSigner":False},{"name":"associatedTokenProgram","isMut":False,"isSigner":False},{"name":"eventAuthority","isMut":False,"isSigner":False},{"name":"program","isMut":False,"isSigner":False}],"args":[]}],"accounts":[{"name":"Dca","type":{"kind":"struct","fields":[{"name":"user","type":"publicKey"},{"name":"inputMint","type":"publicKey"},{"name":"outputMint","type":"publicKey"},{"name":"idx","type":"u64"},{"name":"nextCycleAt","type":"i64"},{"name":"inDeposited","type":"u64"},{"name":"inWithdrawn","type":"u64"},{"name":"outWithdrawn","type":"u64"},{"name":"inUsed","type":"u64"},{"name":"outReceived","type":"u64"},{"name":"inAmountPerCycle","type":"u64"},{"name":"cycleFrequency","type":"i64"},{"name":"nextCycleAmountLeft","type":"u64"},{"name":"inAccount","type":"publicKey"},{"name":"outAccount","type":"publicKey"},{"name":"minOutAmount","type":"u64"},{"name":"maxOutAmount","type":"u64"},{"name":"keeperInBalanceBeforeBorrow","type":"u64"},{"name":"dcaOutBalanceBeforeSwap","type":"u64"},{"name":"createdAt","type":"i64"},{"name":"bump","type":"u8"}]}}],"types":[{"name":"WithdrawParams","type":{"kind":"struct","fields":[{"name":"withdrawAmount","type":"u64"},{"name":"withdrawal","type":{"defined":"Withdrawal"}}]}},{"name":"Withdrawal","type":{"kind":"enum","variants":[{"name":"In"},{"name":"Out"}]}}],"events":[{"name":"CollectedFee","fields":[{"name":"userKey","type":"publicKey","index":False},{"name":"dcaKey","type":"publicKey","index":False},{"name":"mint","type":"publicKey","index":False},{"name":"amount","type":"u64","index":False}]},{"name":"Filled","fields":[{"name":"userKey","type":"publicKey","index":False},{"name":"dcaKey","type":"publicKey","index":False},{"name":"inputMint","type":"publicKey","index":False},{"name":"outputMint","type":"publicKey","index":False},{"name":"inAmount","type":"u64","index":False},{"name":"outAmount","type":"u64","index":False},{"name":"feeMint","type":"publicKey","index":False},{"name":"fee","type":"u64","index":False}]},{"name":"Opened","fields":[{"name":"userKey","type":"publicKey","index":False},{"name":"dcaKey","type":"publicKey","index":False},{"name":"inDeposited","type":"u64","index":False},{"name":"inputMint","type":"publicKey","index":False},{"name":"outputMint","type":"publicKey","index":False},{"name":"cycleFrequency","type":"i64","index":False},{"name":"inAmountPerCycle","type":"u64","index":False},{"name":"createdAt","type":"i64","index":False}]},{"name":"Closed","fields":[{"name":"userKey","type":"publicKey","index":False},{"name":"dcaKey","type":"publicKey","index":False},{"name":"inDeposited","type":"u64","index":False},{"name":"inputMint","type":"publicKey","index":False},{"name":"outputMint","type":"publicKey","index":False},{"name":"cycleFrequency","type":"i64","index":False},{"name":"inAmountPerCycle","type":"u64","index":False},{"name":"createdAt","type":"i64","index":False},{"name":"totalInWithdrawn","type":"u64","index":False},{"name":"totalOutWithdrawn","type":"u64","index":False},{"name":"unfilledAmount","type":"u64","index":False},{"name":"userClosed","type":"bool","index":False}]},{"name":"Withdraw","fields":[{"name":"dcaKey","type":"publicKey","index":False},{"name":"inAmount","type":"u64","index":False},{"name":"outAmount","type":"u64","index":False},{"name":"userWithdraw","type":"bool","index":False}]},{"name":"Deposit","fields":[{"name":"dcaKey","type":"publicKey","index":False},{"name":"amount","type":"u64","index":False}]}],"errors":[{"code":6000,"name":"InvalidAmount","msg":"Invalid deposit amount"},{"code":6001,"name":"InvalidCycleAmount","msg":"Invalid deposit amount"},{"code":6002,"name":"InvalidPair","msg":"Invalid pair"},{"code":6003,"name":"TooFrequent","msg":"Too frequent DCA cycle"},{"code":6004,"name":"InvalidMinPrice","msg":"Minimum price constraint must be greater than 0"},{"code":6005,"name":"InvalidMaxPrice","msg":"Maximum price constraint must be greater than 0"},{"code":6006,"name":"InAmountInsufficient","msg":"In amount needs to be more than in amount per cycle"},{"code":6007,"name":"Unauthorized","msg":"Wrong user"},{"code":6008,"name":"NoInATA","msg":"inAta not passed in"},{"code":6009,"name":"NoUserInATA","msg":"userInAta not passed in"},{"code":6010,"name":"NoOutATA","msg":"outAta not passed in"},{"code":6011,"name":"NoUserOutATA","msg":"userOutAta not passed in"},{"code":6012,"name":"InsufficientBalanceInProgram","msg":"Trying to withdraw more than available"},{"code":6013,"name":"InvalidDepositAmount","msg":"Deposit should be more than 0"},{"code":6014,"name":"UserInsufficientBalance","msg":"User has insufficient balance"},{"code":6015,"name":"UnauthorizedKeeper","msg":"Unauthorized Keeper"},{"code":6016,"name":"UnrecognizedProgram","msg":"Unrecognized Program"},{"code":6017,"name":"MathErrors","msg":"Calculation errors"},{"code":6018,"name":"KeeperNotTimeToFill","msg":"Not time to fill"},{"code":6019,"name":"OrderFillAmountWrong","msg":"Order amount wrong"},{"code":6020,"name":"SwapOutAmountBelowMinimum","msg":"Out amount below expectations"},{"code":6021,"name":"WrongAdmin","msg":"Wrong admin"},{"code":6022,"name":"MathOverflow","msg":"Overflow in arithmetic operation"},{"code":6023,"name":"AddressMismatch","msg":"Address Mismatch"},{"code":6024,"name":"ProgramMismatch","msg":"Program Mismatch"},{"code":6025,"name":"IncorrectRepaymentAmount","msg":"Incorrect Repayment Amount"},{"code":6026,"name":"CannotBorrowBeforeRepay","msg":"Cannot Borrow Before Repay"},{"code":6027,"name":"NoRepaymentInstructionFound","msg":"No Repayment Found"},{"code":6028,"name":"MissingSwapInstructions","msg":"Missing Swap Instruction"},{"code":6029,"name":"UnexpectedSwapProgram","msg":"Expected Instruction to use Jupiter Swap Program"},{"code":6030,"name":"UnknownInstruction","msg":"Unknown Instruction"},{"code":6031,"name":"MissingRepayInstructions","msg":"Missing Repay Instruction"},{"code":6032,"name":"KeeperShortchanged","msg":"Keeper Shortchanged"},{"code":6033,"name":"WrongSwapOutAccount","msg":"Jup Swap to Wrong Out Account"},{"code":6034,"name":"WrongTransferAmount","msg":"Transfer amount should be exactly account balance"},{"code":6035,"name":"InsufficientBalanceForRent","msg":"Insufficient balance for rent"},{"code":6036,"name":"UnexpectedSolBalance","msg":"Unexpected SOL amount in intermediate account"},{"code":6037,"name":"InsufficientWsolForTransfer","msg":"Too little WSOL to perform transfer"},{"code":6038,"name":"MissedInstruction","msg":"Did not call initiate_flash_fill"},{"code":6039,"name":"WrongProgram","msg":"Did not call this program's initiate_flash_fill"},{"code":6040,"name":"BalanceNotZero","msg":"Can't close account with balance"},{"code":6041,"name":"UnexpectedWSOLLeftover","msg":"Should not have WSOL leftover in DCA out-token account"},{"code":6042,"name":"IntermediateAccountNotSet","msg":"Should pass in a WSOL intermediate account when transferring SOL"},{"code":6043,"name":"UnexpectedSwapInstruction","msg":"Did not call jup swap"}]} - - def __init__( - self, - async_client: AsyncClient, - keypair: Keypair - ): - self.rpc = async_client - self.keypair = keypair - self.dca_program = AnchorProgram( - idl=Idl.from_json(json.dumps(self.IDL)), - program_id=self.DCA_PROGRAM_ID, - provider=Provider( - connection=self.rpc, - wallet=Wallet(payer=self.keypair), - opts=TxOpts(skip_preflight=True, preflight_commitment=Processed) - ) - ) - - async def get_mint_token_program( - self, - token_mint: Pubkey, - ) -> Pubkey: - """Returns token mint token program from token mint Pubkey. - - Args: - ``token_mint (Pubkey)``: Pubkey of the token mint. - - Returns: - ``Pubkey (Pubkey)``: Mint token program Pubkey. - - Example: - >>> rpc_url = "https://neat-hidden-sanctuary.solana-mainnet.discover.quiknode.pro/2af5315d336f9ae920028bbb90a73b724dc1bbed/" - >>> async_client = AsyncClient(rpc_url) - >>> private_key_string = "tSg8j3pWQyx3TC2fpN9Ud1bS0NoAK0Pa3TC2fpNd1bS0NoASg83TC2fpN9Ud1bS0NoAK0P" - >>> private_key = Keypair.from_bytes(base58.b58decode(private_key_string)) - >>> jupiter = Jupiter(async_client, private_key) - >>> token_mint = Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v") - >>> token_mint_program = await jupiter.dca.get_mint_token_program(token_mint) - - Pubkey( - TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA, - ) - """ - - mint_token_program_info = await self.rpc.get_account_info(token_mint) - mint_token_program = mint_token_program_info.value.owner - return mint_token_program - - async def get_or_create_associated_token_address( - self, - token_mint: Pubkey, - ) -> dict: - """Returns assosciated token address Pubkey with instruction to create it if it doesn't exists. - - Args: - ``token_mint (Pubkey)``: Pubkey of the token mint. - - Returns: - ``Dict``: Associated token address Pubkey and instruction. - - Example: - >>> rpc_url = "https://neat-hidden-sanctuary.solana-mainnet.discover.quiknode.pro/2af5315d336f9ae920028bbb90a73b724dc1bbed/" - >>> async_client = AsyncClient(rpc_url) - >>> private_key_string = "tSg8j3pWQyx3TC2fpN9Ud1bS0NoAK0Pa3TC2fpNd1bS0NoASg83TC2fpN9Ud1bS0NoAK0P" - >>> private_key = Keypair.from_bytes(base58.b58decode(private_key_string)) - >>> jupiter = Jupiter(async_client, private_key) - >>> token_mint = Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v") - >>> associated_token_address = await jupiter.dca.get_or_create_associated_token_address(token_mint) - - {'pubkey': Pubkey( - 2GWpKNsfBq7y2LS9FNpAUWsr6atnywB7JTwRrifMHzwU, - ), 'instruction': Instruction( - Instruction { - program_id: ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL, - accounts: [ - AccountMeta { - pubkey: AyWu89SjZBW1MzkxiREmgtyMKxSkS1zVy8Uo23RyLphX, - is_signer: True, - is_writable: True, - }, - AccountMeta { - pubkey: 2GWpKNsfBq7y2LS9FNpAUWsr6atnywB7JTwRrifMHzwU, - is_signer: False, - is_writable: True, - }, - AccountMeta { - pubkey: AyWu89SjZBW1MzkxiREmgtyMKxSkS1zVy8Uo23RyLphX, - is_signer: False, - is_writable: False, - }, - AccountMeta { - pubkey: EPjFWdd1ufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v, - is_signer: False, - is_writable: False, - }, - AccountMeta { - pubkey: 11111111111111111111111111111111, - is_signer: False, - is_writable: False, - }, - AccountMeta { - pubkey: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA, - is_signer: False, - is_writable: False, - }, - AccountMeta { - pubkey: SysvarRent111111111111111111111111111111111, - is_signer: False, - is_writable: False, - }, - ], - data: [], - }, - )} - """ - - toAccount = get_associated_token_address(self.keypair.pubkey(), token_mint) - accountInfo = await self.rpc.get_account_info(toAccount) - account = accountInfo.value - - if account: - instruction = None - return {'pubkey': toAccount, 'instruction': instruction} - else: - instruction = create_associated_token_account(self.keypair.pubkey(), self.keypair.pubkey(), token_mint) - return {'pubkey': toAccount, 'instruction': instruction} - - async def get_dca_pubkey( - self, - input_mint: Pubkey, - output_mint: Pubkey, - uid: int, - ) -> Pubkey: - """Returns DCA Pubkey to be created. - - Args: - ``input_mint (Pubkey)``: Pubkey of the token to sell. - ``output_mint (Pubkey)``: Pubkey of the token to buy. - ``uid (int)``: A unix timestamp in seconds. - - Returns: - ``Pubkey``: DCA Pubkey to be created. - - Example: - >>> rpc_url = "https://neat-hidden-sanctuary.solana-mainnet.discover.quiknode.pro/2af5315d336f9ae920028bbb90a73b724dc1bbed/" - >>> async_client = AsyncClient(rpc_url) - >>> private_key_string = "tSg8j3pWQyx3TC2fpN9Ud1bS0NoAK0Pa3TC2fpNd1bS0NoASg83TC2fpN9Ud1bS0NoAK0P" - >>> private_key = Keypair.from_bytes(base58.b58decode(private_key_string)) - >>> jupiter = Jupiter(async_client, private_key) - >>> input_mint = Pubkey.from_string("So11111111111111111111111111111111111111112") - >>> output_mint = Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v") - >>> uid = int(time.time()) - >>> dca_pubkey = await jupiter.dca.get_dca_pubkey(input_mint, output_mint, uid) - - Pubkey( - ArotVdXCEw4Zy5ywUVP7ZJBPFvXR8v8Md6jSQK9pLaCb, - ) - """ - - dcaPubKey = Pubkey.find_program_address( - seeds=[ - b'dca', - self.keypair.pubkey().__bytes__(), - input_mint.__bytes__(), - output_mint.__bytes__(), - struct.pack(" Container[Any]: - """Fetch DCA Account Anchor Data - - Args: - ``dca_pubkey (Pubkey)``: Pubkey of the DCA account. - - Returns: - ``Dca``: DCA Account Anchor Data - - Example: - >>> rpc_url = "https://neat-hidden-sanctuary.solana-mainnet.discover.quiknode.pro/2af5315d336f9ae920028bbb90a73b724dc1bbed/" - >>> async_client = AsyncClient(rpc_url) - >>> private_key_string = "tSg8j3pWQyx3TC2fpN9Ud1bS0NoAK0Pa3TC2fpNd1bS0NoASg83TC2fpN9Ud1bS0NoAK0P" - >>> private_key = Keypair.from_bytes(base58.b58decode(private_key_string)) - >>> jupiter = Jupiter(async_client, private_key) - >>> dca_pubkey = Pubkey.from_string("45iYdjmFUHSJCQHnNpWNFF9AjvzRcsQUP9FDBvJCiNS1") - >>> fetch_dca_data = await jupiter.dca.fetch_dca_data(dca_pubkey) - Dca(user=Pubkey( - AyWu89SjZBW1MzkxiREmgtyMKxSkS1zVy8Uo23RyLphX, - ), input_mint=Pubkey( - So11111111111111111111111111111111111111112, - ), output_mint=Pubkey( - EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v, - ), idx=1703051020, next_cycle_at=1703052580, in_deposited=5000000, in_withdrawn=0, out_withdrawn=194361, in_used=2600000, out_received=194361, in_amount_per_cycle=100000, cycle_frequency=60, next_cycle_amount_left=100000, in_account=Pubkey( - 3NFmVtdyxQvmhXa1a82j62dd9kCmKFa3uv3vv7WRQsRY, - ), out_account=Pubkey( - ErFYjASdQ5HVtJoQ3dqrjp8MgFKjSjFVQiRSqBbKT9kJ, - ), min_out_amount=0, max_out_amount=0, keeper_in_balance_before_borrow=0, dca_out_balance_before_swap=0, created_at=1703050997, bump=253) - """ - dca_account_coder = AccountsCoder(idl=Idl.from_json(json.dumps(self.IDL))) - get_dca_account_details = await self.rpc.get_account_info(dca_pubkey) - dca_account_details = get_dca_account_details.value.data - dca_account_decoded_details = dca_account_coder.decode(dca_account_details) - return dca_account_decoded_details - - async def create_dca( - self, - input_mint: Pubkey, - output_mint: Pubkey, - total_in_amount: int, - in_amount_per_cycle: int, - cycle_frequency: int, - min_out_amount_per_cycle: int=None, - max_out_amount_per_cycle: int=None, - start_at: int=0, - ) -> dict: - """Setting up a DCA account with signing and sending the transaction. - - Args: - ``input_mint (Pubkey)``: Pubkey of the token to sell. - ``output_mint (Pubkey)``: Pubkey of the token to buy. - ``total_in_amount (int)``: Total input mint amount to sell. - ``in_amount_per_cycle (int)``: Input mint amount to sell each time. For e.g. if you are trying to buy SOL using 100 USDC every day over 10 days, in_amount_per_cycle should be 100*10**6. - ``cycle_frequency (int)``: The number of seconds between each periodic buys. For e.g. if you are trying to DCA on a daily basis, cycle_frequency should be 60*60*24 = 86,400. - ``min_out_amount_per_cycle (int)``: Optional field. Following the examples above, let's say you only want to buy SOL if SOL is below SOL-USDC $20, that means for each cycle, with every 100 USDC, you want to receive a minimum of 100 / 20 = 5 SOL. You can then pass 5 * LAMPORTS_PER_SOL as argument here. This ensures that you receive > 5 SOL for each order. - ``max_out_amount_per_cycle (int)``: This is just the inverse scenario of min_out_amount_per_cycle. While max_out_amount_per_cycle is a little counter intuitive, it can be used by advanced traders / investors who believe an asset is at risk of further decline in prices if it goes beyond a certain threshold. Say in the case of output mint being a stablecoin, if the stablecoin drops to $0.5, you will get more buying into it, but that may not necessary be a good thing since the risk of a stablecoin going to $0 is very real if it could depeg to $0.5. This is where max_out_amount_per_cycle could be useful. - ``start_at (int)``: Optional field. Unix timestamp in seconds of when you would like DCA to start. Pass 0 if you want to start immediately or pass a future time as a unix timestamp in seconds. - - Returns: - ``Dict``: Transaction hash and DCA Account Pubkey. - - Example: - >>> rpc_url = "https://neat-hidden-sanctuary.solana-mainnet.discover.quiknode.pro/2af5315d336f9ae920028bbb90a73b724dc1bbed/" - >>> async_client = AsyncClient(rpc_url) - >>> private_key_string = "tSg8j3pWQyx3TC2fpN9Ud1bS0NoAK0Pa3TC2fpNd1bS0NoASg83TC2fpN9Ud1bS0NoAK0P" - >>> private_key = Keypair.from_bytes(base58.b58decode(private_key_string)) - >>> jupiter = Jupiter(async_client, private_key) - >>> input_mint = Pubkey.from_string("So11111111111111111111111111111111111111112") - >>> output_mint = Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v") - >>> total_in_amount = 5_000_000 - >>> in_amount_per_cycle = 100 - >>> cycle_frequency = 60 - >>> min_out_amount_per_cycle = 0 - >>> max_out_amount_per_cycle = 0 - >>> start = 0 - >>> create_dca = await jupiter.dca.create_dca(input_mint, output_mint, total_in_amount, in_amount_per_cycle, cycle_frequency, min_out_amount_per_cycle, max_out_amount_per_cycle, start) - - { - 'dca_pubkey': Pubkey(Duop8ynu7WozpmLUsc1pAq6gobS3vdxe8GJMFzF8rY56,), - 'transaction_hash': '5zFwgyHExYcWLTgqh6GMDPML2mPHzmJUFfsVD882tYd4oGhekiDufcBZSbcoNFKxvhRLQt8WwYU4SsW8fCefYmHf' - } - """ - - pre_instructions = [] - post_instructions = [] - - input_token_program, output_token_program = await self.get_mint_token_program(input_mint), await self.get_mint_token_program(output_mint) - user_input_account = get_associated_token_address(self.keypair.pubkey(), input_mint) - - if input_mint == WRAPPED_SOL_MINT: - input_mint_ata = await self.get_or_create_associated_token_address(input_mint) - transfer_IX = transfer(TransferParams( - from_pubkey=self.keypair.pubkey(), - to_pubkey=user_input_account, - lamports=total_in_amount - )) - sync_native_IX = sync_native(SyncNativeParams( - program_id=input_token_program, - account=user_input_account - )) - - if input_mint_ata['instruction']: - pre_instructions.append(input_mint_ata['instruction']) - post_instructions.append(close_account( - CloseAccountParams( - program_id=input_mint_ata['pubkey'], - account=self.keypair.pubkey(), - dest=self.keypair.pubkey(), - owner=self.keypair.pubkey() - ) - )) - - pre_instructions.append(transfer_IX) - pre_instructions.append(sync_native_IX) - - if output_mint != WRAPPED_SOL_MINT: - output_mint_ata = await self.get_or_create_associated_token_address(output_mint) - - if output_mint_ata['instruction']: - pre_instructions.append(output_mint_ata['instruction']) - - uid = int(time.time()) - dca_pubkey = await self.get_dca_pubkey(input_mint, output_mint, uid) - - accounts = { - 'dca': dca_pubkey, - 'user': self.keypair.pubkey(), - 'payer': self.keypair.pubkey(), - 'input_mint': input_mint, - 'output_mint': output_mint, - 'user_ata': user_input_account, - 'in_ata': get_associated_token_address(dca_pubkey, input_mint), - 'out_ata': get_associated_token_address(dca_pubkey, output_mint), - 'system_program': Pubkey.from_string("11111111111111111111111111111111"), - 'token_program': Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"), - 'associated_token_program': Pubkey.from_string("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"), - 'event_authority': Pubkey.from_string("Cspp27eGUDMXxPEdhmEXFVRn6Lt1L7xJyALF3nmnWoBj"), - 'program': self.DCA_PROGRAM_ID - } - - transaction = await self.dca_program.rpc['open_dca']( - uid, - total_in_amount, - in_amount_per_cycle, - cycle_frequency, - min_out_amount_per_cycle, - max_out_amount_per_cycle, - start_at, - False, - ctx=Context( - accounts=accounts, - signers=[self.keypair], - pre_instructions=pre_instructions, - # post_instructions=post_instructions, - options=TxOpts(skip_preflight=False, preflight_commitment=Processed) - ) - ) - - return {'dca_pubkey': dca_pubkey, 'transaction_hash': str(transaction)} - - async def close_dca( - self, - dca_pubkey: Pubkey, - ) -> str: - """Close DCA Account with signing and sending the transaction. - - Args: - ``dca_pubkey (Pubkey)``: Pubkey of the DCA account to be closed. - - Returns: - ``str``: transaction hash of the DCA account closed. - - Example: - >>> rpc_url = "https://neat-hidden-sanctuary.solana-mainnet.discover.quiknode.pro/2af5315d336f9ae920028bbb90a73b724dc1bbed/" - >>> async_client = AsyncClient(rpc_url) - >>> private_key_string = "tSg8j3pWQyx3TC2fpN9Ud1bS0NoAK0Pa3TC2fpNd1bS0NoASg83TC2fpN9Ud1bS0NoAK0P" - >>> private_key = Keypair.from_bytes(base58.b58decode(private_key_string)) - >>> jupiter = Jupiter(async_client, private_key) - >>> dca_pubkey = Pubkey.from_string("45iYdjmFUHSJCQHnNpWNFF9AjvzRcsQUP9FDBvJCiNS1") - >>> close_dca = await jupiter.dca.close_dca(dca_pubkey) - HXiWtTPLjgtiuNoAN7CEfyDyftdsAnMfuQ93Yp1vukgBbdU1Lb2Bo59p48PVr7CMhxPDwGQbsfjvKT5HXXQfvE2 - """ - dca_account = await self.fetch_dca_data(dca_pubkey) - input_mint = dca_account.input_mint - output_mint = dca_account.output_mint - input_token_program, output_token_program = await self.get_mint_token_program(input_mint), await self.get_mint_token_program(output_mint) - user_input_account = get_associated_token_address(self.keypair.pubkey(), input_mint) - user_output_account = get_associated_token_address(self.keypair.pubkey(), output_mint) - reserve_input_account = get_associated_token_address(dca_pubkey, input_mint) - reserve_output_account = get_associated_token_address(dca_pubkey, output_mint) - - accounts = { - 'user': self.keypair.pubkey(), - 'dca': dca_pubkey, - 'input_mint': input_mint, - 'output_mint': output_mint, - 'in_ata': reserve_input_account, - 'out_ata': reserve_output_account, - 'user_in_ata': user_input_account, - 'user_out_ata': user_output_account, - 'system_program': Pubkey.from_string("11111111111111111111111111111111"), - 'token_program': Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"), - 'associated_token_program': Pubkey.from_string("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"), - 'event_authority': Pubkey.from_string("Cspp27eGUDMXxPEdhmEXFVRn6Lt1L7xJyALF3nmnWoBj"), - 'program': self.DCA_PROGRAM_ID - } - transaction = await self.dca_program.rpc['close_dca']( - ctx=Context( - accounts=accounts, - signers=[self.keypair], - # pre_instructions=pre_instructions, - # post_instructions=post_instructions, - options=TxOpts(skip_preflight=False, preflight_commitment=Processed) - ) - ) - return str(transaction) - - @staticmethod - async def fetch_user_dca_accounts( - wallet_address: str, - status: int - ) -> dict: - """Returns all DCA Accounts from a wallet address - - Args: - ``wallet_address (str)``: Wallet address. - ``status (int)``: 0 = DCA Running | 1 = DCA Done - - Returns: - ``dict``: all DCA Accounts from the wallet address. - - Example: - >>> wallet_address = "AyWu89SjZBW1MzkxiREmgtyMKxSkS1zVy8Uo23RyLphX" - >>> status = 0 - >>> user_dca_accounts = await Jupiter_DCA.fetch_user_dca_accounts(wallet_address, status) - { - 'ok': True, - 'data': { - 'dcaAccounts': [ - { - 'id': 202513, - 'createdAt': '2023-12-18T12:39:40.000Z', - 'updatedAt': '2023-12-18T12:39:42.265Z', - 'userKey': 'AyWu89SjZBW1MzkxiREmgtyMKxSkS1zVy8Uo23RyLphX', - 'dcaKey': 'FTG9eN99uJJBqBtcz1bR6pGfj2Pb3yNAZmGYXggcAgio', - 'inputMint': 'So11111111111111111111111111111111111111112', - 'outputMint': 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', - 'inDeposited': '1000000', - 'inAmountPerCycle': '100', - 'cycleFrequency': '60', - 'closeTxHash': '', - 'openTxHash': '2bwo4ds3Xpiwr9gLptXVFTcxnz2rP9pu3fAppNn3E61g33tprBCy6X8PT3SaXMn7fpG2c5CRw1LWGMEz3ik5SgnP', - 'status': 0, - 'inWithdrawn': '0', - 'outWithdrawn': '0', - 'unfilledAmount': '1000000', - 'userClosed': False, - 'fills': [] - } - ] - } - } - """ - user_dca_accounts = httpx.get(f"https://dca-api.jup.ag/user/{wallet_address}/dca?status={status}", timeout=Timeout(timeout=30.0)).json() - return user_dca_accounts - - @staticmethod - async def fetch_dca_account_fills_history( - dca_account_address: str, - ) -> dict: - """Returns all DCA Account fills history - - Args: - ``dca_account_address (str)``: DCA Account address. - - Returns: - ``dict``: all DCA Account fills history. - - Example: - >>> dca_account_address = "C91FGJAvQgeaXka1exMihC5qChwdcJzFemFVQutv4dev" - >>> dca_account_fills_history = await Jupiter_DCA.fetch_dca_fills_history(dca_account_address) - { - 'ok': True, - 'data': { - 'fills': [ - { - 'userKey': 'AyWu89SjZBW1MzkxiREmgtyMKxSkS1zVy8Uo23RyLphX', - 'dcaKey': 'C91FGJAvQgeaXka1exMihC5qChwdcJzFemFVQutv4dev', - 'inputMint': 'So11111111111111111111111111111111111111112', - 'outputMint': 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', - 'inAmount': '100000', - 'outAmount': '7540', - 'feeMint': 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' - 'fee': '7', - 'txId': '48kC4ZnkPpiRc6T3eVKYghmUERa2geC2e9FvGbVjDMaNkbrDJ3tj36GMkNdi1AkXkqrAHoDZcLW5SFjQEZcKB2NB', - 'confirmedAt': 1703055843 - } - ] - } - } - """ - dca_account_fills_history = httpx.get(f"https://dca-api.jup.ag/dca/{dca_account_address}/fills", timeout=Timeout(timeout=30.0)).json() - return dca_account_fills_history - - @staticmethod - async def get_available_dca_tokens( - ) -> list: - """Get available tokens for DCA. - - Returns: - ``list``: all available tokens from https://cache.jup.ag/top-tokens - - Example: - >>> available_dca_tokens = await Jupiter_DCA.get_available_dca_tokens() - """ - available_dca_tokens = httpx.get(f"https://cache.jup.ag/top-tokens", timeout=Timeout(timeout=30.0)).json() - return available_dca_tokens - -class Jupiter(): - - ENDPOINT_APIS_URL = { - "QUOTE": "https://quote-api.jup.ag/v6/quote?", - "SWAP": "https://quote-api.jup.ag/v6/swap", - "OPEN_ORDER": "https://jup.ag/api/limit/v1/createOrder", - "CANCEL_ORDERS": "https://jup.ag/api/limit/v1/cancelOrders", - "QUERY_OPEN_ORDERS": "https://jup.ag/api/limit/v1/openOrders?wallet=", - "QUERY_ORDER_HISTORY": "https://jup.ag/api/limit/v1/orderHistory", - "QUERY_TRADE_HISTORY": "https://jup.ag/api/limit/v1/tradeHistory" - } - - def __init__( - self, - async_client: AsyncClient, - keypair: Keypair - ): - self.dca = Jupiter_DCA(async_client, keypair) - self.rpc = async_client - self.keypair = keypair - - async def quote( - self, - input_mint: Pubkey, - output_mint: Pubkey, - amount: int, - slippage_bps: int=None, - swap_mode: str="ExactIn", - only_direct_routes: bool=False, - as_legacy_transaction: bool=False, - exclude_dexes: list=None, - max_accounts: int=None - ) -> dict: - """Get the best swap route for a token trade pair sorted by largest output token amount from https://quote-api.jup.ag/v6/quote - - Args: - Required: - ``input_mint (Pubkey)``: Input token mint Pubkey\n - ``output_mint (Pubkey)``: Output token mint Pubkey\n - ``amount (int)``: The API takes in amount in integer and you have to factor in the decimals for each token by looking up the decimals for that token. For example, USDC has 6 decimals and 1 USDC is 1000000 in integer when passing it in into the API.\n - Optionals: - ``slippage_bps (int)``: The slippage % in BPS. If the output token amount exceeds the slippage then the swap transaction will fail.\n - ``swap_mode (str)``: (ExactIn or ExactOut) Defaults to ExactIn. ExactOut is for supporting use cases where you need an exact token amount, like payments. In this case the slippage is on the input token.\n - ``only_direct_routes (bool)``: Default is False. Direct Routes limits Jupiter routing to single hop routes only.\n - ``as_legacy_transaction (bool)``: Default is False. Instead of using versioned transaction, this will use the legacy transaction.\n - ``exclude_dexes (list)``: Default is that all DEXes are included. You can pass in the DEXes that you want to exclude in a list. For example, ['Aldrin','Saber'].\n - ``max_accounts (int)``: Find a route given a maximum number of accounts involved, this might dangerously limit routing ending up giving a bad price. The max is an estimation and not the exact count. - - Returns: - ``dict``: returns best swap route - - Example: - >>> rpc_url = "https://neat-hidden-sanctuary.solana-mainnet.discover.quiknode.pro/2af5315d336f9ae920028bbb90a73b724dc1bbed/" - >>> async_client = AsyncClient(rpc_url) - >>> private_key_string = "tSg8j3pWQyx3TC2fpN9Ud1bS0NoAK0Pa3TC2fpNd1bS0NoASg83TC2fpN9Ud1bS0NoAK0P" - >>> private_key = Keypair.from_bytes(base58.b58decode(private_key_string)) - >>> jupiter = Jupiter(async_client, private_key) - >>> input_mint = Pubkey.from_string("So11111111111111111111111111111111111111112") - >>> output_mint = Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v") - >>> amount = 5_000_000 - >>> quote = await jupiter.quote(input_mint, output_mint, amount) - { - 'inputMint': 'So11111111111111111111111111111111111111112', - 'inAmount': '5000000', - 'outputMint': 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', - 'outAmount': '353237', - 'otherAmountThreshold':'351471', - 'swapMode': 'ExactIn', - 'slippageBps': 50, - 'platformFee': None, - 'priceImpactPct': '0', - 'routePlan': [{'swapInfo': {'ammKey': 'Cx8eWxJAaCQAFVmv1mP7B2cVie2BnkR7opP8vUh23Wcr', 'label': 'Lifinity V2', 'inputMint': 'So11111111111111111111111111111111111111112', 'outputMint': 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', 'inAmount': '5000000', 'outAmount': '353237', 'feeAmount': '1000', 'feeMint': 'So11111111111111111111111111111111111111112'}, 'percent': 100}], - 'contextSlot': 236625263, - 'timeTaken': 0.069434356} - """ - - quote_url = self.ENDPOINT_APIS_URL['QUOTE'] + "inputMint=" + input_mint.__str__() + "&outputMint=" + output_mint.__str__() + "&amount=" + str(amount) + "&swapMode=" + swap_mode + "&onlyDirectRoutes=" + str(only_direct_routes).lower() + "&asLegacyTransaction=" + str(as_legacy_transaction).lower() - if slippage_bps: - quote_url += "&slippageBps=" + str(slippage_bps) - if exclude_dexes: - quote_url += "&excludeDexes=" + ','.join(exclude_dexes).lower() - if max_accounts: - quote_url += "&maxAccounts=" + str(max_accounts) - - quote_response = httpx.get(url=quote_url).json() - return quote_response - - async def swap( - self, - input_mint: Pubkey, - output_mint: Pubkey, - amount: int=0, - wrap_unwrap_sol: bool=True, - slippage_bps: int=0, - swap_mode: str="ExactIn", - only_direct_routes: bool=False, - as_legacy_transaction: bool=False, - exclude_dexes: list=None, - max_accounts: int=None - ) -> str: - """Perform a swap. - - Args: - Required: - ``input_mint (Pubkey)``: Input token mint Pubkey\n - ``output_mint (Pubkey)``: Output token mint Pubkey\n - ``amount (int)``: The API takes in amount in integer and you have to factor in the decimals for each token by looking up the decimals for that token. For example, USDC has 6 decimals and 1 USDC is 1000000 in integer when passing it in into the API.\n - Optionals: - ``wrap_unwrap_sol (bool)``: Auto wrap and unwrap SOL. Default is True.\n - ``slippage_bps (int)``: The slippage % in BPS. If the output token amount exceeds the slippage then the swap transaction will fail.\n - ``swap_mode (str)``: (ExactIn or ExactOut) Defaults to ExactIn. ExactOut is for supporting use cases where you need an exact token amount, like payments. In this case the slippage is on the input token.\n - ``only_direct_routes (bool)``: Default is False. Direct Routes limits Jupiter routing to single hop routes only.\n - ``as_legacy_transaction (bool)``: Default is False. Instead of using versioned transaction, this will use the legacy transaction.\n - ``exclude_dexes (list)``: Default is that all DEXes are included. You can pass in the DEXes that you want to exclude in a list. For example, ['Aldrin','Saber'].\n - ``max_accounts (int)``: Find a route given a maximum number of accounts involved, this might dangerously limit routing ending up giving a bad price. The max is an estimation and not the exact count. - - Returns: - ``str``: returns serialized transactions to perform the swap from https://quote-api.jup.ag/v6/swap - - Example: - >>> rpc_url = "https://neat-hidden-sanctuary.solana-mainnet.discover.quiknode.pro/2af5315d336f9ae920028bbb90a73b724dc1bbed/" - >>> async_client = AsyncClient(rpc_url) - >>> private_key_string = "tSg8j3pWQyx3TC2fpN9Ud1bS0NoAK0Pa3TC2fpNd1bS0NoASg83TC2fpN9Ud1bS0NoAK0P" - >>> private_key = Keypair.from_bytes(base58.b58decode(private_key_string)) - >>> jupiter = Jupiter(async_client, private_key) - >>> input_mint = Pubkey.from_string("So11111111111111111111111111111111111111112") - >>> output_mint = Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v") - >>> amount = 5_000_000 - >>> transaction_data = await jupiter.swap(user_public_key, input_mint, output_mint, amount) - AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAJDpQzg6Gwmq0Gtgp4+LWUVz0yQOAuHGNJAGTs0dcqEMVCoh2aSWdVMvcatcojrWtwXATiOw7/o5hE7NFuy3p8vgLfsLhf7Ff9NofcPgIyAbMytm5ggTyKwmR+JqgXUXARVfefILshj4ZhFSjUfRpiSI47mVNFUq9v5NOOCWSEZJZM/GHGfBesEb9blQsf7DnKodziY279S/OPkZf0/OalnPEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMGRm/lIRcy/+ytunLDm+e8jOW7xfcSayxDmzpAAAAABHnVW/IxwG7udMVuzmgVB/2xst6j9I5RArHNola8E48Gm4hX/quBhPtof2NGGMA12sQ53BrrO1WYoPAAAAAAAQbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCpT0tsDkEI/SpqJHjq4KzFnbIbtO31EcFiz2AtHgwJAfuMlyWPTiSJ8bs9ECkUjg2DC1oTmdr/EIQEjnvY2+n4WbQ/+if11/ZKdMCbHylYed5LCas238ndUUsyGqezjOXoxvp6877brTo9ZfNqq8l0MbG75MLS9uDkfKYCA0UvXWHmraeknnR8/memFAZWZHeDMQG7C5ZFLxolWUniPl6SYgcGAAUCwFwVAAYACQNIDQAAAAAAAAsGAAMACAUJAQEFAgADDAIAAAAgTgAAAAAAAAkBAwERBx8JCgADAQIECA0HBwwHGREBAhUOFxMWDxIQFAoYCQcHJMEgmzNB1pyBBwEAAAATZAABIE4AAAAAAACHBQAAAAAAADIAAAkDAwAAAQkB1rO1s+JVEuIRoGsE8f2MlAkFWssCkimIonlHpLV2w4gKBwKRTE0SjIeLSwIICg== - """ - - quoteResponse = await self.quote( - input_mint=input_mint, - output_mint=output_mint, - amount=amount, - slippage_bps=slippage_bps, - swap_mode=swap_mode, - only_direct_routes=only_direct_routes, - as_legacy_transaction=as_legacy_transaction, - exclude_dexes=exclude_dexes, - max_accounts=max_accounts - ) - transaction_parameters = { - "quoteResponse": quoteResponse, - "userPublicKey": self.keypair.pubkey(), - "wrapUnwrapSOL": wrap_unwrap_sol - } - transaction_data = httpx.post(url=self.ENDPOINT_APIS_URL['SWAP'], json=transaction_parameters).json()['swapTransaction'] - return transaction_data - - async def open_order( - self, - input_mint: Pubkey, - output_mint: Pubkey, - in_amount: int=0, - out_amount: int=0, - expired_at: int=None - ) -> dict: - """Open an order. - - Args: - Required: - ``input_mint (Pubkey)``: Input token mint Pubkey\n - ``output_mint (Pubkey)``: Output token mint Pubkey\n - ``in_amount (int)``: The API takes in amount in integer and you have to factor in the decimals for each token by looking up the decimals for that token. For example, USDC has 6 decimals and 1 USDC is 1000000 in integer when passing it in into the API.\n - ``out_amount (int)``: The API takes in amount in integer and you have to factor in the decimals for each token by looking up the decimals for that token. For example, USDC has 6 decimals and 1 USDC is 1000000 in integer when passing it in into the API.\n - Optionals: - ``expired_at (int)``: Deadline for when the limit order expires. It can be either None or Unix timestamp in seconds. - Returns: - ``dict``: transaction_data and signature2 in order to create the limit order. - - Example: - >>> rpc_url = "https://neat-hidden-sanctuary.solana-mainnet.discover.quiknode.pro/2af5315d336f9ae920028bbb90a73b724dc1bbed/" - >>> async_client = AsyncClient(rpc_url) - >>> private_key_string = "tSg8j3pWQyx3TC2fpN9Ud1bS0NoAK0Pa3TC2fpNd1bS0NoASg83TC2fpN9Ud1bS0NoAK0P" - >>> private_key = Keypair.from_bytes(base58.b58decode(private_key_string)) - >>> jupiter = Jupiter(async_client, private_key) - >>> input_mint = Pubkey.from_string("So11111111111111111111111111111111111111112") - >>> output_mint = Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v") - >>> in_amount = 5_000_000 - >>> out_amount = 100_000 - >>> transaction_data = await jupiter.swap(user_public_key, input_mint, output_mint, amount) - { - 'transaction_data': 'AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgEGC5Qzg6Gwmq0Gtgp4+LWUVz0yQOAuHGNJAGTs0dcqEMVCBvqBKhFi2uRFEKYI4zPatxbdm7DylvnQUby9MexSmeAdsqhWUMQ86Ddz4+7pQFooE6wLglATS/YvzOVUNMOqnyAmC8Ioh9cSvEZniys4XY0OyEvxe39gSdHqlHWJQUPMn4prs0EwIc9JznmgzyMliG5PJTvaFYw75ssASGlB2gMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAImg/TLoYktlelMGKAi4mA0icnTD92092qSZhd3wNABMCv4fVqQvV1OYZ3a3bH43JpI5pIln+UAHnO1fyDJwCfIGm4hX/quBhPtof2NGGMA12sQ53BrrO1WYoPAAAAAAAQan1RcZLFxRIYzJTD1K8X9Y2u4Im6H9ROPb2YoAAAAABt324ddloZPZy+FGzut5rBy0he1fWzeROoz1hX7/AKmr+pT0gdwb1ZeE73qr11921UvCtCB3MMpBcLaiY8+u7QEHDAEABAMCCAIHBgUKCRmFbkqvcJ/1nxAnAAAAAAAAECcAAAAAAAAA', - 'signature2': Signature( - 2Pip6gx9FLGVqmRqfAgwJ8HEuCY8ZbUbVERR18vHyxFngSi3Jxq8Vkpm74hS5zq7RAM6tqGUAkf3ufCBsxGXZrUC,) - } - """ - - keypair = Keypair() - transaction_parameters = { - "owner": self.keypair.pubkey().__str__(), - "inputMint": input_mint, - "outputMint": output_mint, - "outAmount": out_amount, - "inAmount": in_amount, - "base": keypair.pubkey().__str__() - } - if expired_at: - transaction_parameters['expiredAt'] = expired_at - transaction_data = httpx.post(url=self.ENDPOINT_APIS_URL['OPEN_ORDER'], json=transaction_parameters).json()['tx'] - raw_transaction = VersionedTransaction.from_bytes(base64.b64decode(transaction_data)) - signature2 = keypair.sign_message(message.to_bytes_versioned(raw_transaction.message)) - return {"transaction_data": transaction_data, "signature2": signature2} - - async def cancel_orders( - self, - orders: list=[] - ) -> str: - """Cancel open orders from a list (max. 10). - - Args: - Required:!: - ``orders (list)``: List of orders to be cancelled. - Returns: - ``str``: returns serialized transactions to cancel orders from https://jup.ag/api/limit/v1/cancelOrders - - Example: - >>> rpc_url = "https://neat-hidden-sanctuary.solana-mainnet.discover.quiknode.pro/2af5315d336f9ae920028bbb90a73b724dc1bbed/" - >>> async_client = AsyncClient(rpc_url) - >>> private_key_string = "tSg8j3pWQyx3TC2fpN9Ud1bS0NoAK0Pa3TC2fpNd1bS0NoASg83TC2fpN9Ud1bS0NoAK0P" - >>> private_key = Keypair.from_bytes(base58.b58decode(private_key_string)) - >>> jupiter = Jupiter(async_client, private_key) - >>> list_orders = [item['publicKey'] for item in await jupiter.query_open_orders()] # Cancel all open orders - >>> transaction_data = await jupiter.cancel_orders(orders=openOrders) - AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAQIlDODobCarQa2Cnj4tZRXPTJA4C4cY0kAZOzR1yoQxUIklPdDonxNd5JDfdYoHE56dvNBQ1SLN90fFZxvVlzZr9DPwpfbd+ANTB35SSvHYVViD27UZR578oC2faxJea7y958guyGPhmEVKNR9GmJIjjuZU0VSr2/k044JZIRklkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAr+H1akL1dTmGd2t2x+NyaSOaSJZ/lAB5ztX8gycAnyBpuIV/6rgYT7aH9jRhjANdrEOdwa6ztVmKDwAAAAAAEG3fbh12Whk9nL4UbO63msHLSF7V9bN5E6jPWFfv8AqW9ZjNTy3JS6YYFodCWqtWH80+eLPmN4igHrkYHIsdQfAQUHAQIAAwQHBghfge3wCDHfhA== - """ - - transaction_parameters = { - "owner": self.keypair.pubkey().__str__(), - "feePayer": self.keypair.pubkey().__str__(), - "orders": orders - } - transaction_data = httpx.post(url=self.ENDPOINT_APIS_URL['CANCEL_ORDERS'], json=transaction_parameters).json()['tx'] - return transaction_data - - @staticmethod - async def query_open_orders( - wallet_address: str, - input_mint: str=None, - output_mint: str=None - ) -> list: - """ - Query open orders from self.keypair public address. - - Args: - Required: - ``wallet_address (str)``: Wallet address. - Optionals: - ``input_mint (str)``: Input token mint address. - ``output_mint (str)``: Output token mint address. - Returns: - ``list``: returns open orders list from https://jup.ag/api/limit/v1/openOrders - - Example: - >>> list_open_orders = await Jupiter.query_open_orders("AyWu89SjZBW1MzkxiREmgtyMKxSkS1zVy8Uo23RyLphX") - [ - { - 'publicKey': '3ToRYxxMHN3CHkbqWHcbXBCBLNqmDeLoubGGfNKGSCDL', - 'account': { - 'maker': 'AyWu89SjZBW1MzkxiREmgtyMKxSkS1zVy8Uo23RyLphX', - 'inputMint': 'So11111111111111111111111111111111111111112', - 'outputMint': 'AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3', - 'oriInAmount': '10000', - 'oriOutAmount': '10000', - 'inAmount': '10000', - 'outAmount': '10000', - 'expiredAt': None, - 'base': 'FghAhphJkhT74PXFQAz3QKqGVGA72Y2gUeVHU7QRw31c' - } - } - ] - """ - - query_openorders_url = "https://jup.ag/api/limit/v1/openOrders?wallet=" + wallet_address - if input_mint: - query_openorders_url += "inputMint=" + input_mint - if output_mint: - query_openorders_url += "outputMint" + output_mint - - list_open_orders = httpx.get(query_openorders_url, timeout=Timeout(timeout=30.0)).json() - return list_open_orders - - @staticmethod - async def query_orders_history( - wallet_address: str, - cursor: int=None, - skip: int=None, - take: int=None - ) -> list: - """ - Query orders history from self.keypair public address. - - Args: - Required: - ``wallet_address (str)``: Wallet address. - Optionals: - ``cursor (int)``: Pointer to a specific result in the data set. - ``skip (int)``: Number of records to skip from the beginning. - ``take (int)``: Number of records to retrieve from the current position. - Returns: - ``list``: returns open orders list from https://jup.ag/api/limit/v1/orderHistory - - Example: - >>> list_orders_history = await Jupiter.query_orders_history("AyWu89SjZBW1MzkxiREmgtyMKxSkS1zVy8Uo23RyLphX") - [ - { - 'id': 1639144, - 'orderKey': '3ToRYxxMHN3CHkbqWHcbXBCBLNqmDeLoubGGfNKGSCDL', - 'maker': 'AyWu89SjZBW1MzkxiREmgtyMKxSkS1zVy8Uo23RyLphX', - 'inputMint': 'So11111111111111111111111111111111111111112', - 'outputMint': 'AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3', - 'inAmount': '10000', - 'oriInAmount': '10000', - 'outAmount': '10000', - 'oriOutAmount': '10000', - 'expiredAt': None, - 'state': 'Cancelled', - 'createTxid': '4CYy8wZG2aRPctL9do7UBzaK9w4EDLJxGkkU1EEAx4LYNYW7j7Kyet2vL4q6cKK7HbJNHp6QXzLQftpTiDdhtyfL', - 'cancelTxid': '83eN6Lm41t2VWUchm1T6hWX2qK3sf39XzPGbxV9s2WjBZfdUADQdRGg2Y1xAKn4igMJU1xRPCTgUhnm6qFUPWRc', - 'updatedAt': '2023-12-18T15:55:30.617Z', - 'createdAt': '2023-12-18T15:29:34.000Z' - } - ] - """ - - query_orders_history_url = "https://jup.ag/api/limit/v1/orderHistory" + "?wallet=" + wallet_address - if cursor: - query_orders_history_url += "?cursor=" + str(cursor) - if skip: - query_orders_history_url += "?skip=" + str(skip) - if take: - query_orders_history_url += "?take=" + str(take) - - list_orders_history = httpx.get(query_orders_history_url, timeout=Timeout(timeout=30.0)).json() - return list_orders_history - - @staticmethod - async def query_trades_history( - wallet_address: str, - input_mint: str=None, - output_mint: str=None, - cursor: int=None, - skip: int=None, - take: int=None - ) -> list: - """ - Query trades history from a public address. - - Args: - Required: - ``wallet_address (str)``: Wallet address. - Optionals: - ``input_mint (str)``: Input token mint address. - ``output_mint (str)``: Output token mint address. - ``cursor (int)``: Pointer to a specific result in the data set. - ``skip (int)``: Number of records to skip from the beginning. - ``take (int)``: Number of records to retrieve from the current position. - Returns: - ``list``: returns trades history list from https://jup.ag/api/limit/v1/tradeHistory - - Example: - >>> list_trades_history = await Jupiter.query_trades_history("AyWu89SjZBW1MzkxiREmgtyMKxSkS1zVy8Uo23RyLphX") - [ - { - 'id': 10665592, - 'inAmount': - '10000000', - 'outAmount': '675870652', - 'txid': '5rmA1S5MDAVdRYWeVgUWYFp6pYuy5vwrYpRJUJdhjoWnuuheeg1YwqK6P5H6u4tv99cUwQttSBYm6kjSNHJGENgb', - 'updatedAt': '2023-12-13T15:39:04.800Z', - 'createdAt': '2023-12-13T15:37:08.000Z', - 'order': { - 'id': 1278268, - 'orderKey': '3bGykFCMWPNQDTRVBdKBbZuVHqNB5z5XaphkRHLWYmE5', - 'inputMint': 'So11111111111111111111111111111111111111112', - 'outputMint': '8XSsNvaKU9FDhYWAv7Yc7qSNwuJSzVrXBNEk7AFiWF69' - } - } - ] - """ - - query_tradeHistoryUrl = "https://jup.ag/api/limit/v1/tradeHistory" + "?wallet=" + wallet_address - if input_mint: - query_tradeHistoryUrl += "inputMint=" + input_mint - if output_mint: - query_tradeHistoryUrl += "outputMint" + output_mint - if cursor: - query_tradeHistoryUrl += "?cursor=" + cursor - if skip: - query_tradeHistoryUrl += "?skip=" + skip - if take: - query_tradeHistoryUrl += "?take=" + take - - tradeHistory = httpx.get(query_tradeHistoryUrl, timeout=Timeout(timeout=30.0)).json() - return tradeHistory - - @staticmethod - async def get_indexed_route_map( - ) -> dict: - """ - Retrieve an indexed route map for all the possible token pairs you can swap between. - - Args: - Optionals: - ``input_mint (str)``: Input token mint Pubkey.\n - ``output_mint (str)``: Output token mint Pubkey.\n - ``cursor (int)``: Pointer to a specific result in the data set.\n - ``skip (int)``: Number of records to skip from the beginning.\n - ``take (int)``: Number of records to retrieve from the current position. - Returns: - ``dict``: indexed route map for all the possible token pairs you can swap betwee from https://quote-api.jup.ag/v6/indexed-route-map - - Example: - >>> indexed_route_map = await Jupiter.get_indexed_route_map() - """ - - indexed_route_map = httpx.get("https://quote-api.jup.ag/v6/indexed-route-map", timeout=Timeout(timeout=30.0)).json() - return indexed_route_map - - @staticmethod - async def get_tokens_list( - list_type: str="strict", - banned_tokens: bool=False - ) -> dict: - """ - The Jupiter Token List API is an open, collaborative, and dynamic token list to make trading on Solana more transparent and safer for users and developers.\n - There are two types of list:\n - ``strict``\n - - Only tokens that are tagged "old-registry", "community", or "wormhole" verified.\n - - No unknown and banned tokens.\n - ``all``\n - - Everything including unknown/untagged tokens that are picked up automatically.\n - - It does not include banned tokens by default.\n - - Often, projects notice that the token got banned and withdraw liquidity. As our lists are designed for trading, banned tokens that used to, but no longer meet our minimum liquidity requirements will not appear in this response. - - Args: - Optionals: - ``list_type (str)``: Default is "strict" (strict/all). - ``banned_tokens (bool)``: Only if list_type is "all" - Returns: - ``dict``: indexed route map for all the possible token pairs you can swap betwee from https://token.jup.ag/{list_type} - - Example: - >>> tokens_list = await Jupiter.get_tokens_list() - """ - - tokens_list_url = "https://token.jup.ag/" + list_type - if banned_tokens is True: - tokens_list_url += "?includeBanned=true" - tokens_list = httpx.get(tokens_list_url, timeout=Timeout(timeout=30.0)).json() - return tokens_list - - @staticmethod - async def get_all_tickers( - ) -> dict: - """Returns all tickers (cached for every 2-5 mins) from https://stats.jup.ag/coingecko/tickers - - Returns: - ``dict``: all tickers(cached for every 2-5 mins) - - Example: - >>> all_tickers_list = await Jupiter.get_all_tickers() - """ - all_tickers_list = httpx.get("https://stats.jup.ag/coingecko/tickers", timeout=Timeout(timeout=30.0)).json() - return all_tickers_list - - @staticmethod - async def get_all_swap_pairs( - ) -> dict: - """Returns all swap pairs (cached for every 2-5 mins) from https://stats.jup.ag/coingecko/pairs - - Returns: - ``dict``: all swap pairs - - Example: - >>> all_swap_pairs_list = await Jupiter.get_all_swap_pairs() - """ - all_swap_pairs_list = httpx.get("https://stats.jup.ag/coingecko/pairs", timeout=Timeout(timeout=30.0)).json() - return all_swap_pairs_list - - @staticmethod - async def get_swap_pairs( - input_mint: str, - output_mint: str, - ) -> dict: - """Returns swap pairs for input token and output token - - Args: - Required: - ``input_mint (str)``: Input token mint address.\n - ``output_mint (str)``: Output token mint address.\n - - Returns: - ``dict``: all swap pairs for input token and output token - - Example: - >>> swap_pairs_list = await Jupiter.get_swap_pairs("So11111111111111111111111111111111111111112", "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v") - """ - swap_pairs_url = "https://stats.jup.ag/coingecko/tickers?ticker_id=" + input_mint + "_" + output_mint - swap_pairs_list = httpx.get(swap_pairs_url, timeout=Timeout(timeout=30.0)).json() - return swap_pairs_list - - @staticmethod - async def get_token_stats_by_date( - token: str, - date: str, - ) -> list: - """Returns swap pairs for input token and output token - - Args: - Required: - ``token (str)``: Input token mint address.\n - ``date (str)``: YYYY-MM-DD format date.\n - - Returns: - ``list``: all swap pairs for input token and output token - - Example: - >>> token_stats_by_date = await Jupiter.get_swap_pairs("B5mW68TkDewnKvWNc2trkmmdSRxcCjZz3Yd9BWxQTSRU", "2022-04-1") - """ - token_stats_by_date_url = "https://stats.jup.ag/token-ledger/" + token + "/" + date - token_stats_by_date = httpx.get(token_stats_by_date_url, timeout=Timeout(timeout=30.0)).json() - return token_stats_by_date - - @staticmethod - async def get_jupiter_stats( - unit_of_time: str, - ) -> dict: - """Stats for the unit of time specified. - - Args: - Required: - ``unit_of_time (str)``: Unit of time: day/week/month - - Returns: - ``dict``: stats for the unit of time specified. - - Example: - >>> jupiter_stats = await Jupiter.get_jupiter_stats("day") - """ - jupiter_stats_url = "https://stats.jup.ag/info/" + unit_of_time - jupiter_stats = httpx.get(jupiter_stats_url, timeout=Timeout(timeout=30.0)).json() - return jupiter_stats - - @staticmethod - async def get_token_price( - input_mint: str, - output_mint: str=None, - ) -> dict: - """The Jupiter Price API aims to make getting precise and real-time pricing for all SPL tokens as powerful and simple as possible. - - Args: - Required: - ``input_mint (str)``: Input token mint name or address. - Optionals: - ``output_mint (str)``: Output token mint name or address. - - Returns: - ``dict``: id, mintSymbol, vsToken, vsTokenSymbol, price, timeTaken - - Example: - >>> token_price = await Jupiter.get_jupiter_stats("So11111111111111111111111111111111111111112", "USDC") - { - 'So11111111111111111111111111111111111111112': { - 'id': 'So11111111111111111111111111111111111111112', - 'mintSymbol': 'SOL', - 'vsToken': 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', - 'vsTokenSymbol': 'USDC', - 'price': 71.893496709 - } - } - """ - token_prices_url = "https://price.jup.ag/v4/price?ids=" + input_mint - if output_mint: - token_prices_url += "&vsToken=" + output_mint - token_prices = httpx.get(token_prices_url, timeout=Timeout(timeout=30.0)).json()['data'] - return token_prices - - @staticmethod - async def program_id_to_label( - ) -> dict: - """Returns a dict, which key is the program id and value is the label.\n - This is used to help map error from transaction by identifying the fault program id.\n - With that, we can use the exclude_dexes or dexes parameter for swap. - - Returns: - ``dict``: program_id and label - - Example: - >>> program_id_to_label_list = await Jupiter.program_id_to_label() - """ - program_id_to_label_list = httpx.get("https://quote-api.jup.ag/v6/program-id-to-label", timeout=Timeout(timeout=30.0)).json() - return program_id_to_label_list diff --git a/src/dist/jupiter-python-sdk-0.0.1.1.tar.gz b/src/dist/jupiter-python-sdk-0.0.1.1.tar.gz deleted file mode 100644 index 7af4e5e..0000000 Binary files a/src/dist/jupiter-python-sdk-0.0.1.1.tar.gz and /dev/null differ diff --git a/src/dist/jupiter_python_sdk-0.0.1-py3-none-any.whl b/src/dist/jupiter_python_sdk-0.0.1-py3-none-any.whl deleted file mode 100644 index 6cfbc18..0000000 Binary files a/src/dist/jupiter_python_sdk-0.0.1-py3-none-any.whl and /dev/null differ diff --git a/src/jupiter_python_sdk.egg-info/PKG-INFO b/src/jupiter_python_sdk.egg-info/PKG-INFO deleted file mode 100644 index 1c159b6..0000000 --- a/src/jupiter_python_sdk.egg-info/PKG-INFO +++ /dev/null @@ -1,146 +0,0 @@ -Metadata-Version: 2.1 -Name: jupiter-python-sdk -Version: 0.0.1.1 -Summary: Jupiter Python SDK -Author: TaoDev -Author-email: taodev3@proton.me -Keywords: python,solana,jupiter,dex,trading,sdk -Classifier: Development Status :: 1 - Planning -Classifier: Intended Audience :: Developers -Classifier: Programming Language :: Python :: 3 -Classifier: Operating System :: Unix -Classifier: Operating System :: MacOS :: MacOS X -Classifier: Operating System :: Microsoft :: Windows -Description-Content-Type: text/markdown - - -
-

🐍 JUPITER PYTHON SDK 🪐

- -
- ---- - -

- - -
- - -
- - -
-

- -# 📖 Introduction -**Jupiter Python SDK** is a Python library that allows you to use most of **[Jupiter](https://jup.ag/) features**.
-It enables executing swaps, limit orders, DCA, swap pairs, tokens prices, fetching wallet infos, stats, data and more!
-This library is using packages like: [solana-py](https://github.com/michaelhly/solana-py), [solders](https://github.com/kevinheavey/solders), [anchorpy](https://github.com/kevinheavey/anchorpy).
-There is documentation inside each function, however, you can access to the [official Jupiter API](https://docs.jup.ag/docs). - -# ⚠️ Disclaimer -**Please note that I'm not responsible for any loss of funds, damages, or other libailities resulting from the use of this software or any associated services.
-This tool is provided for educational purposes only and should not be used as financial advice, it is still in expiremental phase so use it at your own risk.** - -# ✨ Quickstart - -### 🛠️ Installation - -```sh -pip install jupiter-python-sdk -``` -### 📃 General Usage -**Providing the private key and RPC client is not mandatory if you only intend to execute functions for retrieving data.
-Otherwise, this is required, for instance, to open a DCA account or to close one.** -```py -import base58 -from solders.pubkey import Pubkey -from solders.keypair import Keypair -from solana.rpc.async_api import AsyncClient -from jupiter_python_sdk.jupiter import Jupiter, Jupiter_DCA - -async def main(): - private_key = Keypair.from_bytes(base58.b58decode(os.getenv("PRIVATE_KEY"))) # Private key as string - async_client = AsyncClient(os.getenv("RPC_API")) - jupiter = Jupiter(async_client, private_key) - - # EXECUTE A SWAP - swap = await jupiter.swap( - input_mint=Pubkey.from_string("So11111111111111111111111111111111111111112"), - output_mint=Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), - amount=5_000_000, - slippage_bps=1, - ) - # Returns str: serialized transactions to execute the swap. - - # OPEN LIMIT ORDER - open_limit_order = await jupiter.open_order( - input_mint=Pubkey.from_string("So11111111111111111111111111111111111111112"), - output_mint=Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), - in_amount=5_000_000, - out_amount=100_000, - ) - # Returns dict: {'transaction_data': serialized transactions to create the limit order, 'signature2': signature of the account that will be opened} - - # CREATE DCA ACCOUNT - create_dca_account = await jupiter.dca.create_dca( - input_mint=Pubkey.from_string("So11111111111111111111111111111111111111112"), - output_mint=Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), - total_in_amount=5_000_000, - in_amount_per_cycle=100_000, - cycle_frequency=60, - min_out_amount_per_cycle=0, - max_out_amount_per_cycle=0, - start=0 - ) - # Returns DCA Account Pubkey and transaction hash. - - # CLOSE DCA ACCOUNT - close_dca_account = await jupiter.dca.close_dca( - dca_pubkey=Pubkey.from_string("45iYdjmFUHSJCQHnNpWNFF9AjvzRcsQUP9FDBvJCiNS1") - ) - # Returns transaction hash. -``` -### 📜 All available features -```py -- quote -- swap -- open_order -- cancel_orders -- create_dca -- close_dca -- fetch_user_dca_accounts -- fetch_dca_account_fills_history -- get_available_dca_tokens -- fetch_dca_data -- query_open_orders -- query_orders_history -- query_trades_history -- get_jupiter_stats -- get_token_price -- get_indexed_route_map -- get_tokens_list -- get_all_tickers -- get_all_swap_pairs -- get_swap_pairs -- get_token_stats_by_date -- program_id_to_label -``` - -# 📝 TO-DO -- [ ] Bridge 🌉 -- [ ] Perpetual 💸 - -# 🤝 Contributions -If you are interesting in contributing, fork the repository and submit a pull request in order to merge your improvements into the main repository.
-Contact me for any inquiry, I will reach you as soon as possible.
-[![Discord](https://img.shields.io/badge/Discord-%237289DA.svg?logo=discord&logoColor=white)](https://discord.gg/_taodev_) -[![Twitter](https://img.shields.io/badge/Twitter-%231DA1F2.svg?logo=Twitter&logoColor=white)](https://twitter.com/_TaoDev_) - -# 👑 Donations -This project doesn't include platform fees. If you find value in it and would like to support its development, your donations are greatly appreciated.
-**SOLANA ADDRESS** -```sh -AyWu89SjZBW1MzkxiREmgtyMKxSkS1zVy8Uo23RyLphX -``` diff --git a/src/jupiter_python_sdk.egg-info/SOURCES.txt b/src/jupiter_python_sdk.egg-info/SOURCES.txt deleted file mode 100644 index 7f8379d..0000000 --- a/src/jupiter_python_sdk.egg-info/SOURCES.txt +++ /dev/null @@ -1,8 +0,0 @@ -setup.py -jupiter_python_sdk/__init__.py -jupiter_python_sdk/jupiter.py -jupiter_python_sdk.egg-info/PKG-INFO -jupiter_python_sdk.egg-info/SOURCES.txt -jupiter_python_sdk.egg-info/dependency_links.txt -jupiter_python_sdk.egg-info/requires.txt -jupiter_python_sdk.egg-info/top_level.txt \ No newline at end of file diff --git a/src/jupiter_python_sdk.egg-info/dependency_links.txt b/src/jupiter_python_sdk.egg-info/dependency_links.txt deleted file mode 100644 index 8b13789..0000000 --- a/src/jupiter_python_sdk.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/jupiter_python_sdk.egg-info/requires.txt b/src/jupiter_python_sdk.egg-info/requires.txt deleted file mode 100644 index 6caca51..0000000 --- a/src/jupiter_python_sdk.egg-info/requires.txt +++ /dev/null @@ -1,43 +0,0 @@ -wheel -pyaudio -anchorpy -anchorpy-core -anyio -attrs -base58 -based58 -borsh-construct -cachetools -certifi -charset-normalizer -colorama -construct -construct-typing -h11 -httpcore -httpx -idna -iniconfig -jsonalias -jsonrpcclient -more-itertools -packaging -pluggy -psutil -py -pyheck -pytest -pytest-asyncio -pytest-xprocess -rfc3986 -sniffio -solana -solders -sumtypes -toml -toolz -types-cachetools -typing_extensions -urllib3 -websockets -zstandard diff --git a/src/jupiter_python_sdk.egg-info/top_level.txt b/src/jupiter_python_sdk.egg-info/top_level.txt deleted file mode 100644 index 6ec1073..0000000 --- a/src/jupiter_python_sdk.egg-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -jupiter_python_sdk diff --git a/src/jupiter_python_sdk/README.md b/src/jupiter_python_sdk/README.md deleted file mode 100644 index b9390fb..0000000 --- a/src/jupiter_python_sdk/README.md +++ /dev/null @@ -1,130 +0,0 @@ -
-

🐍 JUPITER PYTHON SDK 🪐

- -
- ---- - -

- - -
- - -
- - -
-

- -# 📖 Introduction -**Jupiter Python SDK** is a Python library that allows you to use most of **[Jupiter](https://jup.ag/) features**.
-It enables executing swaps, limit orders, DCA, swap pairs, tokens prices, fetching wallet infos, stats, data and more!
-This library is using packages like: [solana-py](https://github.com/michaelhly/solana-py), [solders](https://github.com/kevinheavey/solders), [anchorpy](https://github.com/kevinheavey/anchorpy).
-There is documentation inside each function, however, you can access to the [official Jupiter API](https://docs.jup.ag/docs). - -# ⚠️ Disclaimer -**Please note that I'm not responsible for any loss of funds, damages, or other libailities resulting from the use of this software or any associated services.
-This tool is provided for educational purposes only and should not be used as financial advice, it is still in expiremental phase so use it at your own risk.** - -# ✨ Quickstart - -### 🛠️ Installation - -```sh -pip install jupiter-python-sdk -``` -### 📃 General Usage -**Providing the private key and RPC client is not mandatory if you only intend to execute functions for retrieving data.
-Otherwise, this is required, for instance, to open a DCA account or to close one.** -```py -import base58 -from solders.pubkey import Pubkey -from solders.keypair import Keypair -from solana.rpc.async_api import AsyncClient -from jupiter_python_sdk.jupiter import Jupiter, Jupiter_DCA - -async def main(): - private_key = Keypair.from_bytes(base58.b58decode(os.getenv("PRIVATE_KEY"))) # Private key as string - async_client = AsyncClient(os.getenv("RPC_API")) - jupiter = Jupiter(async_client, private_key) - - # EXECUTE A SWAP - swap = await jupiter.swap( - input_mint=Pubkey.from_string("So11111111111111111111111111111111111111112"), - output_mint=Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), - amount=5_000_000, - slippage_bps=1, - ) - # Returns str: serialized transactions to execute the swap. - - # OPEN LIMIT ORDER - open_limit_order = await jupiter.open_order( - input_mint=Pubkey.from_string("So11111111111111111111111111111111111111112"), - output_mint=Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), - in_amount=5_000_000, - out_amount=100_000, - ) - # Returns dict: {'transaction_data': serialized transactions to create the limit order, 'signature2': signature of the account that will be opened} - - # CREATE DCA ACCOUNT - create_dca_account = await jupiter.dca.create_dca( - input_mint=Pubkey.from_string("So11111111111111111111111111111111111111112"), - output_mint=Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), - total_in_amount=5_000_000, - in_amount_per_cycle=100_000, - cycle_frequency=60, - min_out_amount_per_cycle=0, - max_out_amount_per_cycle=0, - start=0 - ) - # Returns DCA Account Pubkey and transaction hash. - - # CLOSE DCA ACCOUNT - close_dca_account = await jupiter.dca.close_dca( - dca_pubkey=Pubkey.from_string("45iYdjmFUHSJCQHnNpWNFF9AjvzRcsQUP9FDBvJCiNS1") - ) - # Returns transaction hash. -``` -### 📜 All available features -```py -- quote -- swap -- open_order -- cancel_orders -- create_dca -- close_dca -- fetch_user_dca_accounts -- fetch_dca_account_fills_history -- get_available_dca_tokens -- fetch_dca_data -- query_open_orders -- query_orders_history -- query_trades_history -- get_jupiter_stats -- get_token_price -- get_indexed_route_map -- get_tokens_list -- get_all_tickers -- get_all_swap_pairs -- get_swap_pairs -- get_token_stats_by_date -- program_id_to_label -``` - -# 📝 TO-DO -- [ ] Bridge 🌉 -- [ ] Perpetual 💸 - -# 🤝 Contributions -If you are interesting in contributing, fork the repository and submit a pull request in order to merge your improvements into the main repository.
-Contact me for any inquiry, I will reach you as soon as possible.
-[![Discord](https://img.shields.io/badge/Discord-%237289DA.svg?logo=discord&logoColor=white)](https://discord.gg/_taodev_) -[![Twitter](https://img.shields.io/badge/Twitter-%231DA1F2.svg?logo=Twitter&logoColor=white)](https://twitter.com/_TaoDev_) - -# 👑 Donations -This project doesn't include platform fees. If you find value in it and would like to support its development, your donations are greatly appreciated.
-**SOLANA ADDRESS** -```sh -AyWu89SjZBW1MzkxiREmgtyMKxSkS1zVy8Uo23RyLphX -``` diff --git a/src/jupiter_python_sdk/jupiter.py b/src/jupiter_python_sdk/jupiter.py index e0de059..918a686 100644 --- a/src/jupiter_python_sdk/jupiter.py +++ b/src/jupiter_python_sdk/jupiter.py @@ -540,30 +540,46 @@ class Jupiter(): def __init__( self, async_client: AsyncClient, - keypair: Keypair + keypair: Keypair, + quote_api_url: str="https://quote-api.jup.ag/v6/quote?", + swap_api_url: str="https://quote-api.jup.ag/v6/swap", + open_order_api_url: str="https://jup.ag/api/limit/v1/createOrder", + cancel_orders_api_url: str="https://jup.ag/api/limit/v1/cancelOrders", + query_open_orders_api_url: str="https://jup.ag/api/limit/v1/openOrders?wallet=", + query_order_history_api_url: str="https://jup.ag/api/limit/v1/orderHistory", + query_trade_history_api_url: str="https://jup.ag/api/limit/v1/tradeHistory", ): self.dca = Jupiter_DCA(async_client, keypair) self.rpc = async_client self.keypair = keypair + + self.ENDPOINT_APIS_URL["QUOTE"] = quote_api_url + self.ENDPOINT_APIS_URL["SWAP"] = swap_api_url + self.ENDPOINT_APIS_URL["OPEN_ORDER"] = open_order_api_url + self.ENDPOINT_APIS_URL["CANCEL_ORDERS"] = cancel_orders_api_url + self.ENDPOINT_APIS_URL["QUERY_OPEN_ORDERS"] = query_open_orders_api_url + self.ENDPOINT_APIS_URL["QUERY_ORDER_HISTORY"] = query_order_history_api_url + self.ENDPOINT_APIS_URL["QUERY_TRADE_HISTORY"] = query_trade_history_api_url async def quote( self, - input_mint: Pubkey, - output_mint: Pubkey, + input_mint: str, + output_mint: str, amount: int, slippage_bps: int=None, swap_mode: str="ExactIn", only_direct_routes: bool=False, as_legacy_transaction: bool=False, exclude_dexes: list=None, - max_accounts: int=None + max_accounts: int=None, + platform_fee_bps: int=None ) -> dict: """Get the best swap route for a token trade pair sorted by largest output token amount from https://quote-api.jup.ag/v6/quote Args: Required: - ``input_mint (Pubkey)``: Input token mint Pubkey\n - ``output_mint (Pubkey)``: Output token mint Pubkey\n + ``input_mint (str)``: Input token mint address\n + ``output_mint (str)``: Output token mint address\n ``amount (int)``: The API takes in amount in integer and you have to factor in the decimals for each token by looking up the decimals for that token. For example, USDC has 6 decimals and 1 USDC is 1000000 in integer when passing it in into the API.\n Optionals: ``slippage_bps (int)``: The slippage % in BPS. If the output token amount exceeds the slippage then the swap transaction will fail.\n @@ -571,7 +587,8 @@ async def quote( ``only_direct_routes (bool)``: Default is False. Direct Routes limits Jupiter routing to single hop routes only.\n ``as_legacy_transaction (bool)``: Default is False. Instead of using versioned transaction, this will use the legacy transaction.\n ``exclude_dexes (list)``: Default is that all DEXes are included. You can pass in the DEXes that you want to exclude in a list. For example, ['Aldrin','Saber'].\n - ``max_accounts (int)``: Find a route given a maximum number of accounts involved, this might dangerously limit routing ending up giving a bad price. The max is an estimation and not the exact count. + ``max_accounts (int)``: Find a route given a maximum number of accounts involved, this might dangerously limit routing ending up giving a bad price. The max is an estimation and not the exact count.\n + ``platform_fee_bps (int)``: If you want to charge the user a fee, you can specify the fee in BPS. Fee % is taken out of the output token. Returns: ``dict``: returns best swap route @@ -582,8 +599,8 @@ async def quote( >>> private_key_string = "tSg8j3pWQyx3TC2fpN9Ud1bS0NoAK0Pa3TC2fpNd1bS0NoASg83TC2fpN9Ud1bS0NoAK0P" >>> private_key = Keypair.from_bytes(base58.b58decode(private_key_string)) >>> jupiter = Jupiter(async_client, private_key) - >>> input_mint = Pubkey.from_string("So11111111111111111111111111111111111111112") - >>> output_mint = Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v") + >>> input_mint = "So11111111111111111111111111111111111111112" + >>> output_mint = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" >>> amount = 5_000_000 >>> quote = await jupiter.quote(input_mint, output_mint, amount) { @@ -601,45 +618,56 @@ async def quote( 'timeTaken': 0.069434356} """ - quote_url = self.ENDPOINT_APIS_URL['QUOTE'] + "inputMint=" + input_mint.__str__() + "&outputMint=" + output_mint.__str__() + "&amount=" + str(amount) + "&swapMode=" + swap_mode + "&onlyDirectRoutes=" + str(only_direct_routes).lower() + "&asLegacyTransaction=" + str(as_legacy_transaction).lower() + quote_url = self.ENDPOINT_APIS_URL['QUOTE'] + "inputMint=" + input_mint + "&outputMint=" + output_mint + "&amount=" + str(amount) + "&swapMode=" + swap_mode + "&onlyDirectRoutes=" + str(only_direct_routes).lower() + "&asLegacyTransaction=" + str(as_legacy_transaction).lower() if slippage_bps: quote_url += "&slippageBps=" + str(slippage_bps) if exclude_dexes: - quote_url += "&excludeDexes=" + ','.join(exclude_dexes).lower() + quote_url += "&excludeDexes=" + ','.join(exclude_dexes) if max_accounts: quote_url += "&maxAccounts=" + str(max_accounts) - + if platform_fee_bps: + quote_url += "&plateformFeeBps=" + platform_fee_bps + quote_response = httpx.get(url=quote_url).json() - return quote_response + try: + quote_response['routePlan'] + return quote_response + except: + raise Exception(quote_response['error']) async def swap( self, input_mint: str, output_mint: str, amount: int=0, + quoteResponse: str=None, wrap_unwrap_sol: bool=True, slippage_bps: int=1, swap_mode: str="ExactIn", + prioritization_fee_lamports: int=None, only_direct_routes: bool=False, as_legacy_transaction: bool=False, exclude_dexes: list=None, - max_accounts: int=None + max_accounts: int=None, + platform_fee_bps: int=None ) -> str: """Perform a swap. Args: Required: - ``input_mint (Pubkey)``: Input token mint Pubkey\n - ``output_mint (Pubkey)``: Output token mint Pubkey\n + ``input_mint (str)``: Input token mint str\n + ``output_mint (str)``: Output token mint str\n ``amount (int)``: The API takes in amount in integer and you have to factor in the decimals for each token by looking up the decimals for that token. For example, USDC has 6 decimals and 1 USDC is 1000000 in integer when passing it in into the API.\n Optionals: + ``prioritizationFeeLamports (int)``: If transactions are expiring without confirmation on-chain, this might mean that you have to pay additional fees to prioritize your transaction. To do so, you can set the prioritizationFeeLamports parameter.\n ``wrap_unwrap_sol (bool)``: Auto wrap and unwrap SOL. Default is True.\n ``slippage_bps (int)``: The slippage % in BPS. If the output token amount exceeds the slippage then the swap transaction will fail.\n ``swap_mode (str)``: (ExactIn or ExactOut) Defaults to ExactIn. ExactOut is for supporting use cases where you need an exact token amount, like payments. In this case the slippage is on the input token.\n ``only_direct_routes (bool)``: Default is False. Direct Routes limits Jupiter routing to single hop routes only.\n ``as_legacy_transaction (bool)``: Default is False. Instead of using versioned transaction, this will use the legacy transaction.\n ``exclude_dexes (list)``: Default is that all DEXes are included. You can pass in the DEXes that you want to exclude in a list. For example, ['Aldrin','Saber'].\n - ``max_accounts (int)``: Find a route given a maximum number of accounts involved, this might dangerously limit routing ending up giving a bad price. The max is an estimation and not the exact count. + ``max_accounts (int)``: Find a route given a maximum number of accounts involved, this might dangerously limit routing ending up giving a bad price. The max is an estimation and not the exact count.\n + ``platform_fee_bps (int)``: If you want to charge the user a fee, you can specify the fee in BPS. Fee % is taken out of the output token. Returns: ``str``: returns serialized transactions to perform the swap from https://quote-api.jup.ag/v6/swap @@ -650,36 +678,40 @@ async def swap( >>> private_key_string = "tSg8j3pWQyx3TC2fpN9Ud1bS0NoAK0Pa3TC2fpNd1bS0NoASg83TC2fpN9Ud1bS0NoAK0P" >>> private_key = Keypair.from_bytes(base58.b58decode(private_key_string)) >>> jupiter = Jupiter(async_client, private_key) - >>> input_mint = Pubkey.from_string("So11111111111111111111111111111111111111112") - >>> output_mint = Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v") + >>> input_mint = "So11111111111111111111111111111111111111112" + >>> output_mint = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" >>> amount = 5_000_000 >>> transaction_data = await jupiter.swap(user_public_key, input_mint, output_mint, amount) AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAJDpQzg6Gwmq0Gtgp4+LWUVz0yQOAuHGNJAGTs0dcqEMVCoh2aSWdVMvcatcojrWtwXATiOw7/o5hE7NFuy3p8vgLfsLhf7Ff9NofcPgIyAbMytm5ggTyKwmR+JqgXUXARVfefILshj4ZhFSjUfRpiSI47mVNFUq9v5NOOCWSEZJZM/GHGfBesEb9blQsf7DnKodziY279S/OPkZf0/OalnPEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMGRm/lIRcy/+ytunLDm+e8jOW7xfcSayxDmzpAAAAABHnVW/IxwG7udMVuzmgVB/2xst6j9I5RArHNola8E48Gm4hX/quBhPtof2NGGMA12sQ53BrrO1WYoPAAAAAAAQbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCpT0tsDkEI/SpqJHjq4KzFnbIbtO31EcFiz2AtHgwJAfuMlyWPTiSJ8bs9ECkUjg2DC1oTmdr/EIQEjnvY2+n4WbQ/+if11/ZKdMCbHylYed5LCas238ndUUsyGqezjOXoxvp6877brTo9ZfNqq8l0MbG75MLS9uDkfKYCA0UvXWHmraeknnR8/memFAZWZHeDMQG7C5ZFLxolWUniPl6SYgcGAAUCwFwVAAYACQNIDQAAAAAAAAsGAAMACAUJAQEFAgADDAIAAAAgTgAAAAAAAAkBAwERBx8JCgADAQIECA0HBwwHGREBAhUOFxMWDxIQFAoYCQcHJMEgmzNB1pyBBwEAAAATZAABIE4AAAAAAACHBQAAAAAAADIAAAkDAwAAAQkB1rO1s+JVEuIRoGsE8f2MlAkFWssCkimIonlHpLV2w4gKBwKRTE0SjIeLSwIICg== """ - quoteResponse = await self.quote( - input_mint=input_mint, - output_mint=output_mint, - amount=amount, - slippage_bps=slippage_bps, - swap_mode=swap_mode, - only_direct_routes=only_direct_routes, - as_legacy_transaction=as_legacy_transaction, - exclude_dexes=exclude_dexes, - max_accounts=max_accounts - ) + if quoteResponse is None: + quoteResponse = await self.quote( + input_mint=input_mint, + output_mint=output_mint, + amount=amount, + slippage_bps=slippage_bps, + swap_mode=swap_mode, + only_direct_routes=only_direct_routes, + as_legacy_transaction=as_legacy_transaction, + exclude_dexes=exclude_dexes, + max_accounts=max_accounts, + platform_fee_bps=platform_fee_bps + ) transaction_parameters = { "quoteResponse": quoteResponse, "userPublicKey": self.keypair.pubkey().__str__(), - "wrapUnwrapSOL": wrap_unwrap_sol + "wrapAndUnwrapSol": wrap_unwrap_sol } - transaction_data = httpx.post(url=self.ENDPOINT_APIS_URL['SWAP'], json=transaction_parameters).json()['swapTransaction'] - return transaction_data + if prioritization_fee_lamports: + transaction_parameters.update({"prioritizationFeeLamports": prioritization_fee_lamports}) + transaction_data = httpx.post(url=self.ENDPOINT_APIS_URL['SWAP'], json=transaction_parameters).json() + return transaction_data['swapTransaction'] async def open_order( self, - input_mint: Pubkey, - output_mint: Pubkey, + input_mint: str, + output_mint: str, in_amount: int=0, out_amount: int=0, expired_at: int=None @@ -688,8 +720,8 @@ async def open_order( Args: Required: - ``input_mint (Pubkey)``: Input token mint Pubkey\n - ``output_mint (Pubkey)``: Output token mint Pubkey\n + ``input_mint (str)``: Input token mint address\n + ``output_mint (str)``: Output token mint address\n ``in_amount (int)``: The API takes in amount in integer and you have to factor in the decimals for each token by looking up the decimals for that token. For example, USDC has 6 decimals and 1 USDC is 1000000 in integer when passing it in into the API.\n ``out_amount (int)``: The API takes in amount in integer and you have to factor in the decimals for each token by looking up the decimals for that token. For example, USDC has 6 decimals and 1 USDC is 1000000 in integer when passing it in into the API.\n Optionals: @@ -703,11 +735,11 @@ async def open_order( >>> private_key_string = "tSg8j3pWQyx3TC2fpN9Ud1bS0NoAK0Pa3TC2fpNd1bS0NoASg83TC2fpN9Ud1bS0NoAK0P" >>> private_key = Keypair.from_bytes(base58.b58decode(private_key_string)) >>> jupiter = Jupiter(async_client, private_key) - >>> input_mint = Pubkey.from_string("So11111111111111111111111111111111111111112") - >>> output_mint = Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v") + >>> input_mint = "So11111111111111111111111111111111111111112" + >>> output_mint = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" >>> in_amount = 5_000_000 >>> out_amount = 100_000 - >>> transaction_data = await jupiter.swap(user_public_key, input_mint, output_mint, amount) + >>> transaction_data = await jupiter.open_order(user_public_key, input_mint, output_mint, in_amount, out_amount) { 'transaction_data': 'AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgEGC5Qzg6Gwmq0Gtgp4+LWUVz0yQOAuHGNJAGTs0dcqEMVCBvqBKhFi2uRFEKYI4zPatxbdm7DylvnQUby9MexSmeAdsqhWUMQ86Ddz4+7pQFooE6wLglATS/YvzOVUNMOqnyAmC8Ioh9cSvEZniys4XY0OyEvxe39gSdHqlHWJQUPMn4prs0EwIc9JznmgzyMliG5PJTvaFYw75ssASGlB2gMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAImg/TLoYktlelMGKAi4mA0icnTD92092qSZhd3wNABMCv4fVqQvV1OYZ3a3bH43JpI5pIln+UAHnO1fyDJwCfIGm4hX/quBhPtof2NGGMA12sQ53BrrO1WYoPAAAAAAAQan1RcZLFxRIYzJTD1K8X9Y2u4Im6H9ROPb2YoAAAAABt324ddloZPZy+FGzut5rBy0he1fWzeROoz1hX7/AKmr+pT0gdwb1ZeE73qr11921UvCtCB3MMpBcLaiY8+u7QEHDAEABAMCCAIHBgUKCRmFbkqvcJ/1nxAnAAAAAAAAECcAAAAAAAAA', 'signature2': Signature( diff --git a/src/setup.py b/src/setup.py index e260d2e..9f0540b 100644 --- a/src/setup.py +++ b/src/setup.py @@ -4,10 +4,10 @@ here = os.path.abspath(os.path.dirname(__file__)) -with codecs.open(os.path.join(here, "jupiter_python_sdk/README.md"), encoding="utf-8") as fh: +with codecs.open(os.path.join(here, "README.md"), encoding="utf-8") as fh: long_description = "\n" + fh.read() -VERSION = '0.0.1.1' +VERSION = '0.0.2.0' DESCRIPTION = 'Jupiter Python SDK' LONG_DESCRIPTION = 'This package allows the use of Jupiter decentralized exchange features on Solana using Python.' @@ -21,54 +21,17 @@ long_description_content_type="text/markdown", long_description=long_description, packages=find_packages(), + license=('LICENSE.txt'), install_requires=[ - 'wheel', - 'pyaudio', - 'anchorpy', - 'anchorpy-core', - 'anyio', - 'attrs', 'base58', - 'based58', - 'borsh-construct', - 'cachetools', - 'certifi', - 'charset-normalizer', - 'colorama', - 'construct', - 'construct-typing', - 'h11', - 'httpcore', - 'httpx', - 'idna', - 'iniconfig', - 'jsonalias', - 'jsonrpcclient', - 'more-itertools', - 'packaging', - 'pluggy', - 'psutil', - 'py', - 'pyheck', - 'pytest', - 'pytest-asyncio', - 'pytest-xprocess', - 'rfc3986', - 'sniffio', - 'solana', 'solders', - 'sumtypes', - 'toml', - 'toolz', - 'types-cachetools', - 'typing_extensions', - 'urllib3', - 'websockets', - 'zstandard' + 'solana', + 'httpx', + 'anchorpy', ], keywords=['python', 'solana', 'jupiter', 'dex', 'trading', 'sdk'], classifiers=[ - "Development Status :: 1 - Planning", + "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "Programming Language :: Python :: 3", "Operating System :: Unix",