Giter Club home page Giter Club logo

solana-py's Introduction


Actions Status PyPI version Codecov License: MIT Code style: black

Solana.py

🐍 The Solana Python SDK 🐍

Solana.py is the base Python library for interacting with Solana. You can use it to build transactions and interact with the Solana JSON RPC API, much like you would do with solana-web3.js

It also covers the SPL Token Program.

Latest Documentation.

Note: This library uses many core types from the Solders package which used to be provided by solana-py itself. If you are upgrading from an old version and you're looking for something that was deleted, it's probably in solders now.

βš“οΈŽ See also: AnchorPy, a Python client for Anchor-based programs on Solana. βš“οΈŽ

⚑ Quickstart

Installation

  1. Install Python bindings for the solana-sdk.
pip install solders
  1. Install this package to interact with the Solana JSON RPC API.
pip install solana

General Usage

Note: check out the Solana Cookbook for more detailed examples!

import solana

API Client

from solana.rpc.api import Client

http_client = Client("https://api.devnet.solana.com")

Async API Client

import asyncio
from solana.rpc.async_api import AsyncClient

async def main():
    async with AsyncClient("https://api.devnet.solana.com") as client:
        res = await client.is_connected()
    print(res)  # True

    # Alternatively, close the client explicitly instead of using a context manager:
    client = AsyncClient("https://api.devnet.solana.com")
    res = await client.is_connected()
    print(res)  # True
    await client.close()

asyncio.run(main())

Websockets Client

import asyncio
from asyncstdlib import enumerate
from solana.rpc.websocket_api import connect

async def main():
    async with connect("wss://api.devnet.solana.com") as websocket:
        await websocket.logs_subscribe()
        first_resp = await websocket.recv()
        subscription_id = first_resp[0].result
        next_resp = await websocket.recv()
        print(next_resp)
        await websocket.logs_unsubscribe(subscription_id)

    # Alternatively, use the client as an infinite asynchronous iterator:
    async with connect("wss://api.devnet.solana.com") as websocket:
        await websocket.logs_subscribe()
        first_resp = await websocket.recv()
        subscription_id = first_resp[0].result
        async for idx, msg in enumerate(websocket):
            if idx == 3:
                break
            print(msg)
        await websocket.logs_unsubscribe(subscription_id)

asyncio.run(main())

πŸ”¨ Development

Setup

  1. Install poetry
  2. Install dev dependencies:
poetry install
  1. Activate the poetry shell.
poetry shell

Lint

make lint

Tests

# All tests
make tests
# Unit tests only
make unit-tests
# Integration tests only
make int-tests

solana-py's People

Contributors

02agarwalt avatar abacus-x avatar broper2 avatar crypt0miester avatar dboures avatar diceroll123 avatar dpgry avatar dpguoming avatar drbh avatar enzoampil avatar gqln avatar johnheavey avatar kevinheavey avatar kevinji avatar kuznetsov-m avatar leofisg avatar lucasbruder avatar manuelzander avatar michaelhly avatar pietrodn avatar pyz4 avatar sdevkc avatar sebastiantoh avatar somebodyli avatar tejon-melero avatar tkzcm avatar ulmentflam avatar unordered-set avatar whdev1 avatar zb-polysign avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

solana-py's Issues

solana-py does not show my staked SRM tokens

Example: I have 1386.181659 SRM. I stake 1000 SRM at https://stake.projectserum.com/#/, leaving 386.181659 unstaked. Before and after staking, if I look up my SRM address in the Solana explorer, it shows 1386.181659, so the staking action did not 'hide' my SRM. The question is: If I use the solana-py API instead, it only shows 386.18659, so the staked amount is "hidden" and not reported. How can I get the solana-py to show the correct SRM in my account both staked+unstaked?

I am calling this endpoint solana_client.get_token_account_balance() to get these results.

Some questions

Hi,

First of all, sorry for this "issue" which is not really an "issue" but a bunch of questions by a noob :p
I would like to make a python program to interact with pool or farm from different protocols on Solana DEX.

  1. Can I achieve this using solana-py (I think yes)
  2. I read the doc but there is no examples for what I want to achieve, do you have some links to educate myself ?
  3. I saw in the doc that smart contract ID on Solana are called "Program ID", is it the same as a pool/farm address and so we could simply connect to RPC, and make simple transaction on that "Program ID" to swap token for example ?

Thank you for you answers.

Regards,
Mitolius

LICENSE file not included in PyPI packages

The LICENSE file isn't included in the files that get uploaded to PyPI (you'll see if you download and unpack the .tar.gz file from here https://pypi.org/project/solana/#files). This is Bad from a legal perspective and causes problems for tools like conda.

However I couldn't replicate this behaviour: I tried uploading the package to TestPyPI and the LICENSE file was included fine https://test.pypi.org/project/solana1/0.11.0/#files.
What command is being run to upload to PyPI? Is it possible it's using some older version of setuptools or something?

connection broken error

I'm having an issue with the solana library. I'm trying to query "get_program_accounts"
But the connection keeps getting broken by the "remote host"

See the screenshot...

image

It was actually working this morning and I'm quite clueless as of why it doesn't anymore...

It shouldn't be an IP ban issue as I've tried through a few of those...

Thanks!

LICENSE file missing again in 0.11.2

The LICENSE file isn't in the PyPI distribution for 0.11.2. When I run python setup.py sdist it appears in the .tar.gz file. @michaelhly does it appear for you?

I'm using setuptools v57.0.0 and twine v3.4.2.

get_signatures_for_address() returns 'Method not found'

Hi,

I noticed that get_signatures_for_address() has come to return 'Method not found' since yesterday.
My code is as follows, which worked properly several days ago:

from solana.rpc.api import Client

url = "https://api.mainnet-beta.solana.com"
client = Client(url)

account = "8tnpAECxAT9nHBqR1Ba494Ar5dQMPGhL31MmPJz1zZvY"
response = client.get_signatures_for_address(account)
print(response)

Result:

{'jsonrpc': '2.0',
 'error': {'code': -32601, 'message': 'Method not found'},
 'id': 1}

I have tried versions 0.12.0 and 0.12.1 but the result did not change.
Is there something wrong with my code?
If not, is there any Solana network update affecting it?

The minimum code which I extract from the implementation of get_signatures_for_address is as follows, but this also gives the same result:

import os
import json
import requests

url = "https://api.mainnet-beta.solana.com"
endpoint_uri = os.environ.get("SOLANARPC_HTTP_URI", url)

method = "getSignaturesForAddress"
account = "8tnpAECxAT9nHBqR1Ba494Ar5dQMPGhL31MmPJz1zZvY"
opts = {"limit": 1}
params = (account, opts)

headers = {"Content-Type": "application/json"}
data = json.dumps({"jsonrpc": "2.0", "id": 1, "method": method, "params": params})
data_kwarg = "data"
request_kwargs = {"url": endpoint_uri, "headers": headers, data_kwarg: data}

raw_response = requests.post(**request_kwargs)
raw_response.raise_for_status()
decoded = json.loads(raw_response.text)
print(decoded)

Mirgate from Struct library to Construct library

Currently, we used the Python built-in Struct library to parse the instructions, however, this has two downsides:

  1. It's hard to parse the instruction that can be variable length, e.g. _ALLOCATE_WITH_SEED_IDX, _ASSIGN_WITH_SEED_IDX. This is because the total length of the instruction depends on a variable-length string.
  2. The format of the parsing code is a bit hard to read, the reader needs to have a reference to the Struct library or familiar with the library itself. So they need to know that Q corresponds to a 64 bits integer and s corresponds to 1-byte character, etc. And they also need to know what each data types meant.

64 bytes private key for Account

I am initing my account object as follows

private_key = bytes([89,136,139,8,93,189,44,2, ...... , 122,168])
payer = Account(private_key) 

but got the following error:

  File "/Users/yurenji/.pyenv/versions/yurenji3.8/lib/python3.8/site-packages/solana/account.py", line 29, in __init__
    self._secret = public.PrivateKey(key) if key else public.PrivateKey.generate()
  File "/Users/yurenji/.pyenv/versions/yurenji3.8/lib/python3.8/site-packages/nacl/public.py", line 89, in __init__
    raise exc.TypeError(("PrivateKey must be created from a {0} "
nacl.exceptions.TypeError: PrivateKey must be created from a 32 bytes long raw secret key

It seems the private key must be 32 bytes. My account is created with solfare.com, and the private key it generates is 64 bytes.

I wonder is there any plan to support 64 bytes private key?

Invalid param: not a v2.0 Token account

Hi I am trying to use this python wrapper to query information about my solana wallet using the endpoint
"https://solana-api.projectserum.com"

The response when querying the account balance is:
{'jsonrpc': '2.0',
'error': {'code': -32602,
'message': 'Invalid param: not a v2.0 Token account'},
'id': 20}

What is my mistake here?

Initializing spl.token.client.Token()

I'm guessing the program_id is the PublicKey of the program for minting, but what is the first PublicKey (pubkey) in reference to?

class Token(_TokenCore):  # pylint: disable=too-many-public-methods
    """An ERC20-like Token."""

    def __init__(self, conn: Client, pubkey: PublicKey, program_id: PublicKey, payer: Account) -> None:

Required packages not part of setup.py?

I encountered the following error:

$ python serum/main.py 
Traceback (most recent call last):
  File "serum/main.py", line 1, in <module>
    from solana.rpc.api import Client
  File "/home/wangge/.local/share/virtualenvs/serum-py-2TNMkmoi/lib/python3.7/site-packages/solana/rpc/api.py", line 13, in <module>
    from .providers import http
  File "/home/wangge/.local/share/virtualenvs/serum-py-2TNMkmoi/lib/python3.7/site-packages/solana/rpc/providers/http.py", line 10, in <module>
    from ..types import URI, RPCMethod, RPCResponse
  File "/home/wangge/.local/share/virtualenvs/serum-py-2TNMkmoi/lib/python3.7/site-packages/solana/rpc/types.py", line 4, in <module>
    from typing_extensions import Literal, TypedDict  # noqa: F401
ModuleNotFoundError: No module named 'typing_extensions'

I think we probably need to add typing_extensions to setup.py.

Is it possible to generate a 64-byte private key?

solana.account.Account generates new accounts, but it's a 32-byte private key.
And I can't import such a key in Sollet wallet. It requires 64-byte key.

Can I generate a new account with this library and next import in into a Sollet wallet?

Missing "until" parameter within get_confirmed_signature_for_address2()

function doesn't conform to api spec

Expect a pull request from me soonish

https://docs.solana.com/apps/jsonrpc-api#getconfirmedsignaturesforaddress2

<string> - account address as base-58 encoded string
<object> - (optional) Configuration object containing the following fields:
    limit: <number> - (optional) maximum transaction signatures to return (between 1 and 1,000, default: 1,000).
    before: <string> - (optional) start searching backwards from this transaction signature. If not provided the search starts from the top of the highest max confirmed block.
    until: <string> - (optional) search until this transaction signature, if found before limit reached.

get_inflation_governor

I've had some trouble when calling this RPC Method. Here's the error:

AttributeError: 'Client' object has no attribute 'get_inflation_governor'

Although the version I pulled has this method in the Client class (lines 427-442):
`
def get_inflation_governor(self, commitment: Commitment = Max) -> RPCResponse:
"""Returns the current inflation governor.

    :param commitment: which bank state to query. It can be either "max", "root", "single" or "recent".

    >>> solana_client = Client("http://localhost:8899")
    >>> solana_client.get_inflation_governor() # doctest: +SKIP
    {'jsonrpc': '2.0',
     'result': {'foundation': 0.05,
      'foundationTerm': 7.0,
      'initial': 0.15,
      'taper': 0.15,
      'terminal': 0.015},
     'id': 5}
    """
    return self._provider.make_request(RPCMethod("getInflationGovernor"), {self._comm_key: commitment})

`
Not sure if this is on my end.

Also, the docs could use a slight edit. The section about the "get_inflation_rate()" method is a copy of the "get_inflation_governor()" above it:
Capture

To run this project make sure you upgrade your python version

Just writing for helping anyone experiencing installation issues or using python version lower than 3.7
This project will not be able to install the dependencies needed if you are using python version lower than 3.7
I just upgraded to latest python version 3.8.5 and it installs the dependencies and everything runs fine :)

RPC Response structure can probably be improved?

Currently if I do:

http_client = Client("https://api.mainnet-beta.solana.com")
marketAddress = PublicKey('6ibUz1BqSD3f8XP4wEGwoRH4YbYRZ1KDZBeXmrp3KosD');
print(http_client.get_balance(marketAddress))

The result sill be:

{'jsonrpc': '2.0', 'result': {'context': {'slot': 30942520}, 'value': 3535680}, 'id': 1}

However, this is not desirable since the user will still need to know what is the format of the RPC response. I think it's probably better if we can have something similar to what the js client is doing, i.e. having a type that is similar to:

export type RpcResponseAndContext<T> = {
 context: Context;
 value: T;
};

@kevinheavey, Hi Kevin, I have a problem when testing Account()

I tried to input the priavte key string such as "W3VVNx2buS7YYYYYYYYYPksrmDJydgKXXXXXXXXXXXXXXXXbFtyZp4CVxp47eCHCvpZPPPPK2GYFaQvA"(exported from phamton wallet) into Account() to initialize my Account to transfer tokens, but it failed. It seems the the Account() needs a keypair which is a int array such as
keypair = [
... 90, 249, 112, 214, 86, 235, 20, 215, 175, 33, 227, 50, 72, 214, 59, 49,
... 38, 161, 99, 83, 107, 188, 57, 48, 119, 189, 46, 148, 160, 214, 239, 148,
... 219, 250, 20, 106, 35, 41, 118, 107, 89, 96, 195, 15, 153, 248, 223, 6,
... 46, 71, 142, 92, 169, 240, 177, 106, 86, 194, 21, 62, 29, 222, 206, 82]

SO can you help me out to import a Account right with a priavte key string?

many thanks!

Seems like the Python version 3.6.9 is not working

I tried installing and running the package using python version 3.6.9, and it's telling me:

(serum-py) wangge@LAPTOP-7VKNK5IV:~/serum-py$ python --version
Python 3.6.9
(serum-py) wangge@LAPTOP-7VKNK5IV:~/serum-py$ python serum/main.py 
Traceback (most recent call last):
  File "serum/main.py", line 1, in <module>
    from solana.rpc.api import Client
  File "/home/wangge/.local/share/virtualenvs/serum-py-2TNMkmoi/lib/python3.6/site-packages/solana/rpc/api.py", line 2
    from __future__ import annotations
    ^
SyntaxError: future feature annotations is not defined

And according to here, the __future__ is only available after Python 3.7. So we probably need to change the requirement file.

How to transfer SOL to an empty accounts?

When I transfer SOL to an account with some amount of SOL, there are no any problems.

But when I try to transfer to an ampty account, I have such an error:

{'code': -32002, 'message': 'Transaction simulation failed: Attempt to debit an account but found no record of a prior credit.', 'data': {'err': 'AccountNotFound', 'logs': []}}

As I understand, it's necessary to create an account first. I try to do it like this:

client = Client(ENDPOINT)
acc = commons.get_account(PRIVATE_KEY)
tx = Transaction(fee_payer=acc.public_key())
tx.add(
    create_account(
        CreateAccountParams(
            from_pubkey=acc.public_key(),
            new_account_pubkey=PublicKey(ACCOUNT_1),
            lamports=1,
            space=1,
            program_id=SYS_PROGRAM_ID,
        )
    )
)
res = client.send_transaction(tx, acc)
print(res)

But it fails like this:
{'code': -32002, 'message': 'Transaction simulation failed: Error processing Instruction 0: missing required signature for instruction', 'data': {'err': {'InstructionError': [0, 'MissingRequiredSignature']}, 'logs': ['Program 11111111111111111111111111111111 invoke [1]', "Allocate: 'to' account Address { address: 7tDBKbR67f5fzTW8h5CUffa9FQXZhmEPY253wgs34uAe, base: None } must sign", 'Program 11111111111111111111111111111111 failed: missing required signature for instruction']}}

But I want to transfer SOL to an account which is empty I don't know its private key, so I can't sign it. So, how can I transfer SOL to an empty account?

Solana-py consider solana/web3.js signature is invalid

We try to pay fee for our user, so we did the following process

  1. Set our server as fee payer
  2. User partial sign tx in frontend(solana/web3.js)
  3. Serialized tx data and pass to our backend
  4. Server deserialized tx and add_signer(solana-py)
  5. Serialized tx and send raw tx

The step 5 will fail due to solana-py consider the user signature is invalid.
However, if we do step 4 and 5 in JS, it will work.

It looks like JS and Python both use 58encde and 58decode for signatures, so I don't know if I miss something.

Implement Client.get_account_info method?

I looked throught the code, it seems like the get_account_info method is not implemented yet. I can see that the js client has this and it is used in the js-serum.

See here for js Solana client implementation. And the usage in the js-serum client here.

How to encode TransactionInstruction.data for a custom Solana program?

As I understand, https://borsh.io is the recommended way to serialize / deserialize data structures for Solana Rust programs. But what's about client side, for Python?

I've checked https://github.com/near/borsh-py, but it's impossible to install it via pypi.

I've checked your library, you have a lot about serialization/deserialization in solana/_layouts. It looks like it's a private module :)

Are there any other libraries on Python which can do the same result that Rust's borsh do?

Can't create a assigned to program account

I want to write a script that help me to stake RAY on raydium. It needs an account assigned to program, but when I create it shows

{'code': -32602, 'message': 'invalid transaction: index out of bounds'}

I tried the code from this test and it still shows this error.

My code:

import solana.system_program as sp
from solana.publickey import PublicKey
from solana.account import Account
from solana.rpc.api import Client
from solana.transaction import Transaction, TransactionInstruction, AccountMeta

# keypair = my keypair here
cli = Client('https://solana-api.projectserum.com')
account = Account(keypair[:32])
new_account = Account()
print(new_account.public_key())
print(new_account.keypair())
transaction = Transaction()
transaction.add(sp.create_account(sp.CreateAccountParams(
        from_pubkey=account.public_key(),
        new_account_pubkey=new_account.public_key(),
        lamports=cli.get_minimum_balance_for_rent_exemption(88).get('result'),
        space=88,
        program_id=PublicKey('EhhTKczWMGQt46ynNeRX1WfeagwwJd7ufHvCDjRxjo5Q'),
    )))
send_tx = cli.send_transaction(transaction, new_account)
print(send_tx)

AttributeError: transaction has not been signed correctly

I'm trying to send SOL from one account to another in testnet:

import os

import base58
from dotenv import load_dotenv
from solana.account import Account
from solana.publickey import PublicKey
from solana.rpc.api import Client
from solana.system_program import TransferParams, transfer
from solana.transaction import Transaction

load_dotenv()

# example: Fy8WpnXAn2UULUEiN2ip4AS5hCAuhJkDApKwjdaWDDkB
from_address = os.getenv("ADDRESS_0")

# example: 5hKkU1C8WhTEvSRxb9GXp8vQLsaPKFVwo8EcdeKm2ZLiCw3TkaP9N4G7tkh84kpD3ER99eZsPqRTgY2rYqWh6AWB
private_key = os.getenv("PRIVATE_0")

# example: 3TrQtmFtAh52MrSUrgHYajMUaMGebFFNCyaNTj3LGx5N
to_address = os.getenv("ADDRESS_1")

client = Client("https://testnet.solana.com")

acc = Account(base58.b58decode(private_key)[:32])
print(acc.public_key().to_base58().decode() == from_address)  # True. I'm sure that private key is valid for from_address

# check from_address balance
res = client.get_balance(acc.public_key())
print("balance", res["result"]["value"] / 10 ** 9)  # 1000.0, I'm sure than from_address has enough SOL

res = client.get_recent_blockhash()
recent_blockhash = res["result"]["value"]["blockhash"]
print("recent_blockhash", recent_blockhash)  # HXacPFu9CHNqPG3LzP43L4EYHtsL3gAvDPNT6CvhjGZK

tx = Transaction(fee_payer=acc.public_key(), recent_blockhash=recent_blockhash)
tx.add(transfer(TransferParams(from_pubkey=PublicKey(from_address), to_pubkey=PublicKey(to_address), lamports=1 * 10 ** 9)))
tx.sign(acc)

res = client.send_transaction(tx)
#  raise AttributeError("transaction has not been signed correctly")

It fails with such an error:

Traceback (most recent call last):
  File "/Users/max/projects/learn/pypi__solana/t3__transfer_lamports.py", line 39, in <module>
    res = client.send_transaction(tx)
  File "/Users/max/projects/learn/pypi__solana/.venv/lib/python3.9/site-packages/solana/rpc/api.py", line 973, in send_transaction
    return self.send_raw_transaction(txn.serialize(), opts=opts)
  File "/Users/max/projects/learn/pypi__solana/.venv/lib/python3.9/site-packages/solana/transaction.py", line 317, in serialize
    raise AttributeError("transaction has not been signed correctly")
AttributeError: transaction has not been signed correctly

What I'm doing wrong?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.