Beispiel #1
0
def list_transactions(wallet_file, test_mode=True, trezor_mode=False):
    network_settings = get_network_settings(test_mode=test_mode)
    if not trezor_mode:
        (private_key, public_key) = load_wallet(wallet_file=wallet_file)
        k = Keypair.from_secret(secret=private_key)
    else:
        public_key = get_trezor_public_key()
        k = Keypair.from_public_key(public_key=public_key)
    server = Server(network_settings.get("horizon_url"))
    response = server.transactions().for_account(
        account_id=k.public_key).call()
    print(json.dumps(response, indent=4))
from stellar_sdk import Server

server = Server(horizon_url="https://horizon-testnet.stellar.org")
account_id = "GASOCNHNNLYFNMDJYQ3XFMI7BYHIOCFW3GJEOWRPEGK2TDPGTG2E5EDW"
last_cursor = 'now'  # or load where you left off


def tx_handler(tx_response):
    print(tx_response)


for tx in server.transactions().for_account(account_id).cursor(
        last_cursor).stream():
    tx_handler(tx)
class HorizonProvider(StellarProvider):
    """
    Horizon is a software that allows you to query nodes via http.
    This should be the only thing we need since horizon also indexes the data it holds.
    """

    def __init__(self, horizon_url='https://horizon-testnet.stellar.org/'):
        self.server = Server(horizon_url=horizon_url)

    def _make_request(self, fun, *args, **kwargs):
        """
        Used to make the request to the horizon server.
        It will catch the library specific exceptions and raise the exceptions used in this project.
        :param fun: api call to make
        :param args: args for the api call
        :param kwargs: args for the api call
        :return: response form the api call
        """
        try:
            return fun(*args, **kwargs)
        except stellar_sdk.exceptions.ConnectionError:
            raise ConnectionException('Could not connect to the server')
        except stellar_sdk.exceptions.NotFoundError as e:
            # This exception is used by the check_account_created function
            if fun == self.server.load_account:
                raise e
            raise RequestException('Check the request params, the resource could not be found')
        except stellar_sdk.exceptions.BadRequestError as e:
            raise RequestException('Your request had an error')
        except stellar_sdk.exceptions.BadResponseError:
            raise RequestException('The server response had an error')

    def submit_transaction(self, tx):
        return self._make_request(self.server.submit_transaction, tx)['hash']

    def get_balance(self, address):
        # We only care about the native token right now.
        return self._make_request(self.server.accounts().account_id(address).call)['balances'][0]['balance']

    def get_transactions(self, address):
        response = self._make_request(
            self.server.transactions().for_account(address).limit(200).include_failed(True).call)
        transactions = response['_embedded']['records']
        return self._normalize_transactions(transactions)

    def _normalize_transactions(self, transactions):
        """
        Transform a list of Transactions from the api into the format used in this project
        :param transactions: List of transactions from the api
        :return: A list of Transaction objects
        """
        transactions_to_return = []
        for tx in transactions:
            transactions_to_return.append(self._normalize_transaction(tx))
        return transactions_to_return

    def _normalize_transaction(self, tx) -> Transaction:
        """
        Transform a transaction from the api into a transaction object this project uses.
        :param tx: transaction from api
        :return: Transaction object
        """
        max_time_bound_string = tx.get('valid_before')
        # the date we get from the api ends with z to indicate utc we have to remove this to parse it
        max_time_bound = None if max_time_bound_string is None else datetime.fromisoformat(max_time_bound_string[:-1])
        min_time_bound_string = tx.get('valid_after')
        min_time_bound = None if min_time_bound_string is None else datetime.fromisoformat(min_time_bound_string[:-1])
        return Transaction(
            hash=tx['hash'],
            date_time=datetime.fromisoformat(tx['created_at'][:-1]),
            fee=int(tx['fee_charged']),
            operation_count=tx['operation_count'],
            source_account=tx['source_account'],
            succeeded=tx['successful'],
            sequence_number=tx['source_account_sequence'],
            transaction_envelope=tx['envelope_xdr'],
            ledger_nr=tx['ledger'],
            min_time_bound=min_time_bound,
            max_time_bound=max_time_bound
        )

    def get_base_fee(self):
        return self._make_request(self.server.fetch_base_fee)

    def get_ledger_height(self):
        response = self._make_request(self.server.ledgers().limit(1).order().call)
        return response['_embedded']['records'][0]['sequence']

    def get_account_sequence(self, address):
        return int(self._make_request(self.server.accounts().account_id(address).call)["sequence"])

    def check_account_created(self, address) -> bool:
        try:
            self._make_request(self.server.load_account, address)
        except NotFoundError:
            return False
        return True
Beispiel #4
0
class StellarWallet:
    """
    Stellar Hot Wallet Handler on chain
    for live net use self.server = Server(horizon_url="https://horizon.stellar.org")  # Live network

    """

    def __init__(self, horizon_url: str, integrated_coins):
        helpers = Helpers()
        secret_details = helpers.read_json_file(file_name="walletSecrets.json")  # Load Stellar wallet secrets
        public_details = helpers.read_json_file(file_name="hotWallets.json")  # Load hot wallet details
        self.integrated_coins = integrated_coins
        self.public_key = public_details["xlm"]
        self.dev_key = public_details["xlmDev"]
        self.private_key = secret_details['stellar']
        self.root_keypair = Keypair.from_secret(self.private_key)
        self.root_account = Account(account_id=self.root_keypair.public_key, sequence=1)
        self.server = Server(horizon_url=horizon_url)  # Testnet

        # Decide network type
        if horizon_url == "https://horizon-testnet.stellar.org":
            self.network_phrase = Network.TESTNET_NETWORK_PASSPHRASE
            self.network_type = 'testnet'
        else:
            self.network_phrase = Network.PUBLIC_NETWORK_PASSPHRASE
            self.network_type = 'pub-net'

    def create_stellar_account(self):
        """
        Creates inactive stellar account which needs to be activated by depositing lumens
        """
        try:
            key_pair = Keypair.random()
            public_key = key_pair.public_key
            private_key = key_pair.secret
            return {f'address': f'{public_key}',
                    f'secret': f'{private_key}',
                    "network": f'{self.network_type}'}
        except NotFoundError:
            return {}

    def generate_uri(self, address: str, memo: str):

        """
        Returns Transaction as envelope
        """

        return stellar_uri.PayStellarUri(destination=address,
                                         memo=TextMemo(text=memo),
                                         asset=Asset.native(),
                                         network_passphrase=self.network_phrase,
                                         message='Deposit to Discord',
                                         ).to_uri()

    @staticmethod
    def __filter_error(result_code):
        if 'op_no_trust' in result_code:
            return 'no trust'
        elif 'op_no_source_account' in result_code:
            return 'No source account provided'
        else:
            return result_code

    def check_if_account_activate(self, address):
        "Try to load account on the network"
        try:
            self.server.load_account(account_id=address)
            return True
        except NotFoundError:
            return False

    def get_stellar_hot_wallet_details(self):
        """
        Return the stellar hot wallet balance
        :return:
        """
        data = self.server.accounts().account_id(account_id=self.public_key).call()
        if 'status' not in data:
            data.pop('_links')
            data.pop('data')
            data.pop('flags')
            data.pop('last_modified_ledger')
            data.pop('sequence')
            data.pop('subentry_count')
            data.pop('thresholds')
            data.pop('signers')
            data.pop('id')
            data.pop('paging_token')
            return data
        else:
            return {}

    def decode_transaction_envelope(self, envelope_xdr):
        """
        Decode envelope and get details
        Credits to overcat :
        https://stellar.stackexchange.com/questions/3022/how-can-i-get-the-value-of-the-stellar-transaction/3025#3025
        :param envelope_xdr: Xdr envelope from stellar network
        :return: Decoded transaction details
        """
        te = TransactionEnvelope.from_xdr(envelope_xdr, self.network_phrase)
        operations = te.transaction.operations

        # TODO make multiple payments inside one transaction
        for op in operations:
            if isinstance(op, Payment):
                asset = op.asset.to_dict()
                if asset.get('type') == 'native':
                    asset['code'] = 'XLM'  # Appending XLM code to asset incase if native
                asset["amount"] = op.to_xdr_amount(op.amount)
                # TODO count all deposits
                return asset

    def get_incoming_transactions(self, pag=None):
        """
        Gets all incoming transactions and removes certain values
        :return: List of incoming transfers
        """
        data = self.server.transactions().for_account(account_id=self.public_key).include_failed(False).order(
            desc=False).cursor(cursor=pag).limit(200).call()
        to_process = list()
        for tx in data['_embedded']['records']:
            # Get transaction envelope
            if tx['source_account'] != self.public_key and tx['successful'] is True:  # Get only incoming transactions
                tx.pop('_links')
                tx.pop('fee_charged')
                tx.pop('id')
                tx.pop('fee_account')
                tx.pop('fee_meta_xdr')
                tx.pop('ledger')
                tx.pop('max_fee')
                tx.pop('operation_count')
                tx.pop('result_meta_xdr')
                tx.pop('result_xdr')
                tx.pop('signatures')
                tx['asset_type'] = self.decode_transaction_envelope(envelope_xdr=tx['envelope_xdr'])
                tx.pop('envelope_xdr')
                to_process.append(tx)
        return to_process

    @staticmethod
    def check_if_memo(memo):
        """
        Check if memo has been provided
        :param memo:
        :return:
        """
        if memo != 'none':
            return True
        else:
            return False

    def token_withdrawal(self, address, token, amount: str):
        """
        Amount as full
        """

        if token != 'xlm':
            asset_issuer = self.integrated_coins[token.lower()]["assetIssuer"]
        else:
            asset_issuer = None

        source_account = self.server.load_account(self.public_key)
        tx = TransactionBuilder(
            source_account=source_account,
            network_passphrase=self.network_phrase,
            base_fee=self.server.fetch_base_fee()).append_payment_op(
            asset_issuer=asset_issuer,
            destination=address, asset_code=token.upper(), amount=amount).set_timeout(30).build()
        tx.sign(self.root_keypair)
        try:
            resp = self.server.submit_transaction(tx)
            details = self.decode_transaction_envelope(envelope_xdr=resp['envelope_xdr'])
            end_details = {
                "asset": details['code'],
                "explorer": resp['_links']['transaction']['href'],
                "hash": resp['hash'],
                "ledger": resp['ledger'],
                "destination": address,
                "amount": details['amount']
            }
            return end_details
        except exceptions.BadRequestError as e:
            # get operation from result_codes to be processed
            error = self.__filter_error(result_code=e.extras["result_codes"]['operations'])
            return {

                "error": f'{error} with {token.upper()} issuer'
            }

    def establish_trust(self, private_key, token):
        """
        Amount as full
        """
        # Load user secret and get account

        user_key_pair = Keypair.from_secret(private_key)
        root_account = Account(account_id=user_key_pair.public_key, sequence=1)
        public_key = root_account.account_id
        asset_issuer = self.integrated_coins[token.lower()]["assetIssuer"]

        try:
            source_account = self.server.load_account(public_key)
            tx = TransactionBuilder(
                source_account=source_account,
                network_passphrase=self.network_phrase,
                base_fee=self.server.fetch_base_fee()).append_change_trust_op(asset_code=f'{token.upper()}',
                                                                              asset_issuer=asset_issuer).set_timeout(
                30).build()
            tx.sign(private_key)

            self.server.submit_transaction(tx)
            return True
        except exceptions.NotFoundError:
            return False
Beispiel #5
0
from stellar_sdk import Server

server = Server(horizon_url="https://horizon-testnet.stellar.org")

# get a list of transactions that occurred in ledger 1400
transactions = server.transactions().for_ledger(1400).call()
print(transactions)

# get a list of transactions submitted by a particular account
transactions = server.transactions() \
    .for_account(account_id="GASOCNHNNLYFNMDJYQ3XFMI7BYHIOCFW3GJEOWRPEGK2TDPGTG2E5EDW") \
    .call()
print(transactions)