mango-explorer/bin/send-token

90 lines
4.1 KiB
Plaintext
Raw Normal View History

#!/usr/bin/env pyston3
import argparse
import logging
import os
import os.path
import sys
import traceback
import typing
from decimal import Decimal
from solana.publickey import PublicKey
from spl.token.client import Token
from spl.token.constants import TOKEN_PROGRAM_ID
sys.path.insert(0, os.path.abspath(
os.path.join(os.path.dirname(__file__), '..')))
import mango # nopep8
# We explicitly want argument parsing to be outside the main try-except block because some arguments
# (like --help) will cause an exit, which our except: block traps.
parser = argparse.ArgumentParser(description="Sends one of the Group's SPL tokens to a different address.")
mango.Context.add_command_line_parameters(parser)
mango.Wallet.add_command_line_parameters(parser)
parser.add_argument("--token-symbol", type=str, required=True, help="token symbol to send (e.g. ETH)")
parser.add_argument("--address", type=PublicKey,
help="Destination address for the SPL token - can be either the actual token address or the address of the owner of the token address")
parser.add_argument("--quantity", type=Decimal, required=True, help="quantity of token to send")
parser.add_argument("--dry-run", action="store_true", default=False,
help="runs as read-only and does not perform any transactions")
args = parser.parse_args()
logging.getLogger().setLevel(args.log_level)
logging.warning(mango.WARNING_DISCLAIMER_TEXT)
try:
context = mango.Context.from_command_line_parameters(args)
wallet = mango.Wallet.from_command_line_parameters_or_raise(args)
logging.info(f"Context: {context}")
logging.info(f"Wallet address: {wallet.address}")
group = mango.Group.load(context)
group_basket_token = mango.BasketToken.find_by_symbol(group.basket_tokens, args.token_symbol)
group_token = group_basket_token.token
spl_token = Token(context.client, group_token.mint, TOKEN_PROGRAM_ID, wallet.account)
source_accounts = spl_token.get_accounts(wallet.address)
source_account = source_accounts["result"]["value"][0]
source = PublicKey(source_account["pubkey"])
# Is the address an actual token account? Or is it the SOL address of the owner?
possible_dest: typing.Optional[mango.TokenAccount] = mango.TokenAccount.load(context, args.address)
if (possible_dest is not None) and (possible_dest.value.token.mint == group_token.mint):
# We successfully loaded the token account.
destination: PublicKey = args.address
else:
destination_accounts = spl_token.get_accounts(args.address)
if len(destination_accounts["result"]["value"]) == 0:
raise Exception(
f"Could not find destination account using {args.address} as either owner address or token address.")
destination_account = destination_accounts["result"]["value"][0]
destination = PublicKey(destination_account["pubkey"])
owner = wallet.account
amount = int(args.quantity * Decimal(10 ** group_token.decimals))
print("Balance:", source_account["account"]["data"]["parsed"]
["info"]["tokenAmount"]["uiAmountString"], group_token.name)
text_amount = f"{amount} {group_token.name} (@ {group_token.decimals} decimal places)"
print(f"Sending {text_amount}")
print(f" From: {source}")
print(f" To: {destination}")
if args.dry_run:
print("Skipping actual transfer - dry run.")
else:
transfer_response = spl_token.transfer(source, destination, owner, amount)
transaction_id = context.unwrap_transaction_id_or_raise_exception(transfer_response)
print(f"Waiting on transaction ID: {transaction_id}")
context.wait_for_confirmation(transaction_id)
updated_balance = spl_token.get_balance(source)
updated_balance_text = updated_balance["result"]["value"]["uiAmountString"]
print(f"{text_amount} sent. Balance now: {updated_balance_text} {group_token.name}")
except Exception as exception:
logging.critical(f"group-send-token stopped because of exception: {exception} - {traceback.format_exc()}")
except:
logging.critical(f"group-send-token stopped because of uncatchable error: {traceback.format_exc()}")