Last active
February 12, 2022 05:59
-
-
Save Smephite/03233213ce42d1352c83247426b72988 to your computer and use it in GitHub Desktop.
Use this script to claim all sellable tokens offered to you by claimable balances. Now uses ^6.0.0b
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from stellar_sdk import Server, Keypair, TransactionBuilder, Network | |
import stellar_sdk | |
from stellar_sdk.asset import Asset | |
from stellar_sdk.operation.create_claimable_balance import ClaimPredicate | |
from stellar_sdk.operation.path_payment_strict_send import PathPaymentStrictSend | |
from stellar_sdk.signer import Signer | |
import datetime, decimal | |
print(f"Using stellar SDK v{stellar_sdk.__version__}") | |
keypair = Keypair.from_secret(input("Please enter your secret key: ")) | |
server = Server('https://horizon.stellar.org') | |
base_fee = server.fetch_base_fee() | |
acc = server.load_account(keypair.public_key) | |
balances = server.claimable_balances().for_claimant(keypair.public_key).call()['_embedded']['records'] | |
pending_assets = [] | |
tx = TransactionBuilder(source_account=acc, network_passphrase=Network.PUBLIC_NETWORK_PASSPHRASE, base_fee=base_fee*10) | |
# base fee is bidding system, we most likely will not pay more then the {base_fee} | |
operations = 0 | |
for balance in balances: | |
if operations > 96: | |
print("This iteration reached the maximum transaction size. Please run the script again to claim any tokens left.") | |
break | |
asset = balance['asset'].split(':') | |
asset = Asset(asset[0], asset[1]) | |
amount = balance['amount'] | |
id = balance['id'] | |
pending_assets.append({'asset': asset, 'amount': amount, 'id': id}) | |
claimants = balance['claimants'] | |
predicate = next(filter(lambda x: x['destination'] == acc.universal_account_id, claimants))['predicate'] | |
if 'unconditional' not in predicate or not predicate['unconditional']: | |
if 'abs_before' in predicate : | |
date = datetime.datetime.strptime(predicate['abs_before'], '%Y-%m-%dT%H:%M:%SZ') | |
if date < datetime.datetime.now(): | |
print(f"{asset.code} was only claimable until {date}") | |
continue | |
asset_info = server.strict_send_paths(source_amount=amount, source_asset=asset, destination=[Asset.native()]).call() | |
available_paths = asset_info['_embedded']['records'] | |
max_path = max(available_paths, key=lambda path: path['destination_amount'], default=None) | |
if max_path is None: | |
print(f"Could not find path for {asset.code}") | |
continue | |
native_amount = decimal.Decimal(max_path['destination_amount']) | |
tx_cost = decimal.Decimal(4*base_fee)/10000000 | |
if native_amount < tx_cost: | |
print(f"The amount gained by this token ({native_amount}) is less then the base fee ({tx_cost}) required to claim it.") | |
continue | |
print(f"{max_path['source_asset_code']} -> {max_path['destination_asset_type']}: {max_path['source_amount']} :: {native_amount}") | |
if len(max_path['path']) != 0: | |
print(f"{max_path}") | |
max_path['path'] = list(map(lambda val: Asset(val.asset_code, val.asset_issuer), max_path['path'])) | |
tx = tx.append_change_trust_op(asset) | |
tx = tx.append_claim_claimable_balance_op(balance_id=id) | |
tx = tx.append_operation(PathPaymentStrictSend( | |
destination=acc.universal_account_id, | |
send_asset=asset, | |
send_amount=amount, | |
dest_min=native_amount, | |
dest_asset=Asset.native(), | |
path=max_path['path'] | |
)) | |
tx = tx.append_change_trust_op(asset, "0") | |
operations += 4 | |
if operations == 0: | |
print("No claimable token was found...") | |
exit() | |
tx = tx.build() | |
tx.sign(keypair) | |
print(tx.to_xdr()) | |
if input("Enter `y` to execute this transaction on pubnet: ") == "y": | |
print(server.submit_transaction(tx)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment