Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how to get number of SPL tokens in a account, help and thx so much !!!!!!! #398

Open
Mrfranken opened this issue Mar 8, 2024 · 5 comments

Comments

@Mrfranken
Copy link

Mrfranken commented Mar 8, 2024

hi, I own USDC and other tokens in my account, I want to get how many USDC in my account, what should I do?
I've tried method "get_token_accounts_by_owner", just like

from solana.rpc.api import Client
from solana.rpc import types

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

token_accounts = http_client.get_token_accounts_by_owner(
    Pubkey.from_string("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"),
    types.TokenAccountOpts(program_id=Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"))
)
print(token_accounts)

but it shows complicated dict, seems solana is so different from evm chain, could u help to give a example? many thx

@caomingpei
Copy link

caomingpei commented Mar 13, 2024

get_token_account_balance may be more suitable for your needs.

For example, system account of circle has may token account, and 3emsAVdmGKERbHjmGfQ6oZ1e35dkf5iYcS6U4CPKFVaa is his token account of USDC.
You may use get_token_account_balance method to get the balance of this kind of account, which represents the USDC balance of your account.

from solana.rpc.api import Client, Pubkey

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

token_accounts = http_client.get_token_account_balance(
    Pubkey.from_string("3emsAVdmGKERbHjmGfQ6oZ1e35dkf5iYcS6U4CPKFVaa")
)
print(token_accounts)

The output is a dict, just like:
GetTokenAccountBalanceResp { context: RpcResponseContext { slot: 253876481, api_version: Some("1.17.21") }, value: UiTokenAmount(UiTokenAmount { ui_amount: Some(296529493.035438), decimals: 6, amount: "296529493035438", ui_amount_string: "296529493.035438" }) }

Well, the amount and decimals show the balance.

@skywalkerscott
Copy link

get_token_account_balance may be more suitable for your needs.

For example, system account of circle has may token account, and 3emsAVdmGKERbHjmGfQ6oZ1e35dkf5iYcS6U4CPKFVaa is his token account of USDC. You may use get_token_account_balance method to get the balance of this kind of account, which represents the USDC balance of your account.

from solana.rpc.api import Client, Pubkey

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

token_accounts = http_client.get_token_account_balance(
    Pubkey.from_string("3emsAVdmGKERbHjmGfQ6oZ1e35dkf5iYcS6U4CPKFVaa")
)
print(token_accounts)

The output is a dict, just like: GetTokenAccountBalanceResp { context: RpcResponseContext { slot: 253876481, api_version: Some("1.17.21") }, value: UiTokenAmount(UiTokenAmount { ui_amount: Some(296529493.035438), decimals: 6, amount: "296529493035438", ui_amount_string: "296529493.035438" }) }

Well, the amount and decimals show the balance.

The method get_token_count_balance does not solve the problem of multiple token balances being returned simultaneously, and the token data returned by the method get_token_counts.by_owner cannot be used.

@caomingpei
Copy link

get_token_account_balance may be more suitable for your needs.
For example, system account of circle has may token account, and 3emsAVdmGKERbHjmGfQ6oZ1e35dkf5iYcS6U4CPKFVaa is his token account of USDC. You may use get_token_account_balance method to get the balance of this kind of account, which represents the USDC balance of your account.

from solana.rpc.api import Client, Pubkey

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

token_accounts = http_client.get_token_account_balance(
    Pubkey.from_string("3emsAVdmGKERbHjmGfQ6oZ1e35dkf5iYcS6U4CPKFVaa")
)
print(token_accounts)

The output is a dict, just like: GetTokenAccountBalanceResp { context: RpcResponseContext { slot: 253876481, api_version: Some("1.17.21") }, value: UiTokenAmount(UiTokenAmount { ui_amount: Some(296529493.035438), decimals: 6, amount: "296529493035438", ui_amount_string: "296529493.035438" }) }
Well, the amount and decimals show the balance.

The method get_token_count_balance does not solve the problem of multiple token balances being returned simultaneously, and the token data returned by the method get_token_counts.by_owner cannot be used.

Yeah, you are right. This problem is collecting all numbers of usdc of one's account. Therefore, need to use the get_token_accounts_by_owner first to find all usdc minted by one's account, and get all token account balance. The following is an update example:

import json
from solana.rpc.api import Client, Pubkey
from solana.rpc.types import TokenAccountOpts

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

# Token Program ID and USDC Mint Address
token_program_id = Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
usdc_mint_address = Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v")
opts = TokenAccountOpts(program_id=token_program_id, mint=usdc_mint_address)

response = http_client.get_token_accounts_by_owner(
    Pubkey.from_string("7VHUFJHWu2CuExkJcJrzhQPJ2oygupTWkL2A2For4BmE"),
    opts
)
token_accounts = json.loads(response.to_json())
all_usdc_accounts = [account['pubkey'] for account in token_accounts['result']['value']]


def get_all_usdc_accounts(all_accounts):
    for address in all_accounts:
        balance = json.loads(http_client.get_token_account_balance(Pubkey.from_string(address)).to_json())
        token_amount = balance['result']['value']['uiAmount']
        print("{}: {}".format(address, token_amount))

get_all_usdc_accounts(all_usdc_accounts)

@skywalkerscott
Copy link

skywalkerscott commented Apr 24, 2024

get_token_account_balance may be more suitable for your needs.
For example, system account of circle has may token account, and 3emsAVdmGKERbHjmGfQ6oZ1e35dkf5iYcS6U4CPKFVaa is his token account of USDC. You may use get_token_account_balance method to get the balance of this kind of account, which represents the USDC balance of your account.

from solana.rpc.api import Client, Pubkey

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

token_accounts = http_client.get_token_account_balance(
    Pubkey.from_string("3emsAVdmGKERbHjmGfQ6oZ1e35dkf5iYcS6U4CPKFVaa")
)
print(token_accounts)

The output is a dict, just like: GetTokenAccountBalanceResp { context: RpcResponseContext { slot: 253876481, api_version: Some("1.17.21") }, value: UiTokenAmount(UiTokenAmount { ui_amount: Some(296529493.035438), decimals: 6, amount: "296529493035438", ui_amount_string: "296529493.035438" }) }
Well, the amount and decimals show the balance.

The method get_token_count_balance does not solve the problem of multiple token balances being returned simultaneously, and the token data returned by the method get_token_counts.by_owner cannot be used.

Yeah, you are right. This problem is collecting all numbers of usdc of one's account. Therefore, need to use the get_token_accounts_by_owner first to find all usdc minted by one's account, and get all token account balance. The following is an update example:

import json
from solana.rpc.api import Client, Pubkey
from solana.rpc.types import TokenAccountOpts

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

# Token Program ID and USDC Mint Address
token_program_id = Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
usdc_mint_address = Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v")
opts = TokenAccountOpts(program_id=token_program_id, mint=usdc_mint_address)

response = http_client.get_token_accounts_by_owner(
    Pubkey.from_string("7VHUFJHWu2CuExkJcJrzhQPJ2oygupTWkL2A2For4BmE"),
    opts
)
token_accounts = json.loads(response.to_json())
all_usdc_accounts = [account['pubkey'] for account in token_accounts['result']['value']]


def get_all_usdc_accounts(all_accounts):
    for address in all_accounts:
        balance = json.loads(http_client.get_token_account_balance(Pubkey.from_string(address)).to_json())
        token_amount = balance['result']['value']['uiAmount']
        print("{}: {}".format(address, token_amount))

get_all_usdc_accounts(all_usdc_accounts)

If the encoding parameter is used jsonParsed, executing the following method will result in an error.

address = Pubkey.from_string("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
program_id = Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
opts = TokenAccountOpts(program_id=program_id, encoding="jsonParsed")
ret = http_client.get_token_accounts_by_owner(address, opts)

The error is like this.

Traceback (most recent call last):
  File "/Users/scott/dev/blockchain-dev/venv/lib/python3.11/site-packages/solana/exceptions.py", line 43, in argument_decorator
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/Users/scott/dev/blockchain-dev/venv/lib/python3.11/site-packages/solana/rpc/providers/http.py", line 49, in make_request
    return _parse_raw(raw, parser=parser)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/scott/dev/blockchain-dev/venv/lib/python3.11/site-packages/solana/rpc/providers/core.py", line 95, in _parse_raw
    parsed = parser.from_json(raw)  # type: ignore
             ^^^^^^^^^^^^^^^^^^^^^
solders.SerdeJSONError: data did not match any variant of untagged enum Resp

@caomingpei
Copy link

get_token_account_balance may be more suitable for your needs.
For example, system account of circle has may token account, and 3emsAVdmGKERbHjmGfQ6oZ1e35dkf5iYcS6U4CPKFVaa is his token account of USDC. You may use get_token_account_balance method to get the balance of this kind of account, which represents the USDC balance of your account.

from solana.rpc.api import Client, Pubkey

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

token_accounts = http_client.get_token_account_balance(
    Pubkey.from_string("3emsAVdmGKERbHjmGfQ6oZ1e35dkf5iYcS6U4CPKFVaa")
)
print(token_accounts)

The output is a dict, just like: GetTokenAccountBalanceResp { context: RpcResponseContext { slot: 253876481, api_version: Some("1.17.21") }, value: UiTokenAmount(UiTokenAmount { ui_amount: Some(296529493.035438), decimals: 6, amount: "296529493035438", ui_amount_string: "296529493.035438" }) }
Well, the amount and decimals show the balance.

The method get_token_count_balance does not solve the problem of multiple token balances being returned simultaneously, and the token data returned by the method get_token_counts.by_owner cannot be used.

Yeah, you are right. This problem is collecting all numbers of usdc of one's account. Therefore, need to use the get_token_accounts_by_owner first to find all usdc minted by one's account, and get all token account balance. The following is an update example:

import json
from solana.rpc.api import Client, Pubkey
from solana.rpc.types import TokenAccountOpts

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

# Token Program ID and USDC Mint Address
token_program_id = Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
usdc_mint_address = Pubkey.from_string("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v")
opts = TokenAccountOpts(program_id=token_program_id, mint=usdc_mint_address)

response = http_client.get_token_accounts_by_owner(
    Pubkey.from_string("7VHUFJHWu2CuExkJcJrzhQPJ2oygupTWkL2A2For4BmE"),
    opts
)
token_accounts = json.loads(response.to_json())
all_usdc_accounts = [account['pubkey'] for account in token_accounts['result']['value']]


def get_all_usdc_accounts(all_accounts):
    for address in all_accounts:
        balance = json.loads(http_client.get_token_account_balance(Pubkey.from_string(address)).to_json())
        token_amount = balance['result']['value']['uiAmount']
        print("{}: {}".format(address, token_amount))

get_all_usdc_accounts(all_usdc_accounts)

If the encoding parameter is used jsonParsed, executing the following method will result in an error.

address = Pubkey.from_string("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
program_id = Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
opts = TokenAccountOpts(program_id=program_id, encoding="jsonParsed")
ret = http_client.get_token_accounts_by_owner(address, opts)

The error is like this.

Traceback (most recent call last):
  File "/Users/scott/dev/blockchain-dev/venv/lib/python3.11/site-packages/solana/exceptions.py", line 43, in argument_decorator
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/Users/scott/dev/blockchain-dev/venv/lib/python3.11/site-packages/solana/rpc/providers/http.py", line 49, in make_request
    return _parse_raw(raw, parser=parser)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/scott/dev/blockchain-dev/venv/lib/python3.11/site-packages/solana/rpc/providers/core.py", line 95, in _parse_raw
    parsed = parser.from_json(raw)  # type: ignore
             ^^^^^^^^^^^^^^^^^^^^^
solders.SerdeJSONError: data did not match any variant of untagged enum Resp

If you would like to get the json format results, perhaps should use the get_token_accounts_by_owner_json_parsed. But this method is unstable (https://michaelhly.com/solana-py/rpc/async_api/#solana.rpc.async_api.AsyncClient.get_token_accounts_by_owner_json_parsed).

As for the encoding parameters in TokenAccountOpts, it seems to only support base58 and base64 now. (https://michaelhly.com/solana-py/rpc/types/#solana.rpc.types.TokenAccountOpts)

The code should update to:

...
opts = TokenAccountOpts(program_id=token_program_id, mint=usdc_mint_address)
response = http_client.get_token_accounts_by_owner_json_parsed(
    Pubkey.from_string("7VHUFJHWu2CuExkJcJrzhQPJ2oygupTWkL2A2For4BmE"),
    opts
)
...

The response is in json format.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants