import json
import sys
import time
import os
import green_gdk as gdk
def main():
verbose = False
original_stderr = None
args = sys.argv[1:]
if '-v' in args or '--verbose' in args:
verbose = True
args = [arg for arg in args if arg not in ['-v', '--verbose']]
if len(args) != 2:
print("Usage: python balance.py [options] <environment> <gaid>")
print("Options:")
print(" -v, --verbose Show detailed output")
sys.exit(1)
environment = args[0].lower()
gaid = args[1]
valid_environments = ['dev', 'test', 'amp']
if environment not in valid_environments:
print(f"Error: Invalid environment '{environment}'")
print(f"Valid environments are: {', '.join(valid_environments)}")
sys.exit(1)
if verbose:
print(f"Using environment: {environment}, GAID: {gaid}")
if not verbose:
original_stderr = sys.stderr
sys.stderr = open(os.devnull, 'w')
try:
gdk.init({
'datadir': '.', 'log_level': 'none' if not verbose else 'warn'
})
except:
gdk.init({
'datadir': '.',
'log_level': 'warn'
})
mnemonics = {
'dev': "vote ball voice juice visit license music off paddle hold suffer beach someone hover wheat boring protect broccoli issue opinion uniform media update arrange",
'test': "hood novel finish couch rack pistol march army gun bring universe unknown hurry famous vote enact inspire whisper violin blur chief into engage cigar",
'amp': "perfect grit monkey disorder cliff exhibit meat giant dream secret liberty walnut later caught snow wasp bulb bind feature couple vault flower credit bundle"
}
mnemonic = mnemonics[environment]
if not gdk.validate_mnemonic(mnemonic):
raise Exception("Invalid mnemonic")
session = gdk.Session({'name': 'testnet-liquid'})
credentials = {'mnemonic': mnemonic}
def login_with_retry(session, credentials, verbose, max_retries=3):
for attempt in range(max_retries):
try:
session.login_user({}, credentials).resolve()
if verbose:
print("Successfully logged in")
return session
except RuntimeError as e:
if 'reconnect required' in str(e) and attempt < max_retries - 1:
if verbose:
print(f"Connection error, retrying... (attempt {attempt + 2}/{max_retries})")
time.sleep(2)
session = gdk.Session({'name': 'testnet-liquid'})
else:
raise
return session
session = login_with_retry(session, credentials, verbose)
subaccounts_result = session.get_subaccounts().resolve()
found_subaccount = False
subaccount_pointer = None
for subaccount in subaccounts_result['subaccounts']:
if subaccount['receiving_id'] == gaid and subaccount['type'] == '2of2_no_recovery':
found_subaccount = True
subaccount_pointer = subaccount['pointer']
if verbose:
print(f"Found matching subaccount for GAID: {gaid} (pointer: {subaccount_pointer})")
break
if not found_subaccount:
error_msg = f"GAID {gaid} not found in environment {environment}"
if verbose:
print(f"Error: {error_msg}")
else:
print(json.dumps({"error": error_msg}))
if not verbose and original_stderr is not None:
sys.stderr.close()
sys.stderr = original_stderr
sys.exit(1)
max_retries = 3
for attempt in range(max_retries):
try:
balance_details = session.get_balance({
'subaccount': subaccount_pointer,
'num_confs': 0 }).resolve()
balances = {}
total_satoshi = 0
if verbose:
print(f"\nBalance details for GAID {gaid}:")
for asset_id, satoshi_value in balance_details.items():
if not isinstance(satoshi_value, (int, float)):
continue
satoshi_amount = int(satoshi_value)
if satoshi_amount == 0:
continue
lbtc_asset_id = '144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49'
if asset_id == 'btc' or asset_id == lbtc_asset_id:
asset_name = 'L-BTC'
btc_amount = satoshi_amount / 100_000_000
balances['L-BTC'] = {
'satoshi': satoshi_amount,
'amount': btc_amount,
'asset_id': asset_id
}
else:
asset_name = f"Asset {asset_id[:8]}..."
balances[asset_name] = {
'satoshi': satoshi_amount,
'asset_id': asset_id
}
total_satoshi += satoshi_amount
if verbose:
if asset_name == 'L-BTC':
print(f" {asset_name}: {satoshi_amount} satoshi ({btc_amount:.8f} L-BTC)")
else:
print(f" {asset_name}: {satoshi_amount} satoshi")
output = {
'gaid': gaid,
'environment': environment,
'balances': balances,
'total_satoshi': total_satoshi
}
if len(balances) == 1 and 'L-BTC' in balances:
output['total_lbtc'] = balances['L-BTC']['amount']
break
except RuntimeError as e:
if 'reconnect required' in str(e) and attempt < max_retries - 1:
if verbose:
print(f"Connection error during balance retrieval, retrying... (attempt {attempt + 2}/{max_retries})")
time.sleep(2)
session = login_with_retry(gdk.Session({'name': 'testnet-liquid'}), credentials, verbose)
else:
raise Exception(f"Error retrieving balance: {e}")
print(json.dumps(output, indent=2))
if not verbose and original_stderr is not None:
sys.stderr.close()
sys.stderr = original_stderr
if __name__ == "__main__":
verbose = '-v' in sys.argv or '--verbose' in sys.argv
try:
main()
except Exception as e:
if verbose:
print(f"\nError: {e}")
import traceback
traceback.print_exc()
else:
print(json.dumps({"error": str(e)}))
sys.exit(1)