def create_stellar_deposit(transaction_id):
    transaction = Transaction.objects.get(id=transaction_id)
    # Assume transaction has valid stellar_account, amount_in, asset.name
    stellar_account = transaction.stellar_account
    payment_amount = transaction.amount_in - transaction.amount_fee
    asset = transaction.asset.name

    # If the given Stellar account does not exist, create
    # the account with at least enough XLM for the minimum
    # reserve and a trust line (recommended 2.01 XLM), update
    # the transaction in our internal database, and return.
    address = Address(stellar_account)
    try:
        address.get()
    except HorizonError as e:
        # 404 code corresponds to Resource Missing.
        if e.status_code == 404:
            starting_balance = settings.ACCOUNT_STARTING_BALANCE
            builder = Builder(secret=settings.STELLAR_ACCOUNT_SEED)
            builder.append_create_account_op(
                destination=stellar_account,
                starting_balance=starting_balance,
                source=settings.STELLAR_ACCOUNT_ADDRESS,
            )
            builder.sign()
            try:
                builder.submit()
            except HorizonError as exception:
                raise exception
            transaction.status = Transaction.STATUS.pending_trust
            transaction.save()
            return

    # If the account does exist, deposit the desired amount of the given
    # asset via a Stellar payment. If that payment succeeds, we update the
    # transaction to completed at the current time. If it fails due to a
    # trustline error, we update the database accordingly. Else, we do not update.
    builder = Builder(secret=settings.STELLAR_ACCOUNT_SEED)
    builder.append_payment_op(
        destination=stellar_account,
        asset_code=asset,
        asset_issuer=settings.STELLAR_ACCOUNT_ADDRESS,
        amount=str(payment_amount),
    )
    builder.sign()
    try:
        builder.submit()
    except HorizonError as exception:
        if TRUSTLINE_FAILURE_XDR in exception.message:
            transaction.status = Transaction.STATUS.pending_trust
            transaction.save()
            return

    # If we reach here, the Stellar payment succeeded, so we
    # can mark the transaction as completed.
    transaction.status = Transaction.STATUS.completed
    transaction.completed_at = now()
    transaction.amount_out = payment_amount
    transaction.save()
Exemple #2
0
def build_generate_trust_wallet_transaction(
        transaction_source_address: str,
        source_address: str,
        destination_address: str,
        xlm_amount: Decimal,
        hot_amount: Decimal = Decimal(0),
        sequence=None,
) -> Tuple[bytes, bytes]:
    """"Build transaction return unsigned XDR and transaction hash.

        Args:
            transaction_source_address: Owner of a transaction.
            source_address: Owner of creator address and payment operations.
            destination_address: wallet id of new wallet.
            xlm_amount: starting xlm_balance of new wallet.
            hot_amount: starting hot balance of new wallet.
    """
    builder = Builder(
        address=transaction_source_address,
        horizon=settings['HORIZON_URL'],
        network=settings['PASSPHRASE'],
        sequence=sequence,
    )
    builder.append_create_account_op(source=source_address,
                                     destination=destination_address,
                                     starting_balance=xlm_amount)
    try:
        builder.append_trust_op(
            source=destination_address,
            destination=settings['ISSUER'],
            code=settings['ASSET_CODE'],
            limit=settings['LIMIT_ASSET'],
        )
    except DecodeError:
        raise web.HTTPBadRequest(reason='Parameter values are not valid.')
    except Exception as e:
        msg = str(e)
        raise web.HTTPInternalServerError(reason=msg)

    if hot_amount > 0:
        builder.append_payment_op(
            source=source_address,
            destination=destination_address,
            asset_code=settings['ASSET_CODE'],
            asset_issuer=settings['ISSUER'],
            amount=hot_amount,
        )

    try:
        unsigned_xdr = builder.gen_xdr()
    except Exception as e:
        raise web.HTTPBadRequest(
            reason='Bad request, Please ensure parameters are valid.')

    tx_hash = builder.te.hash_meta()

    return unsigned_xdr, tx_hash
Exemple #3
0
def build_generate_wallet_transaction(transaction_source_address: str,
                                      source_address: str,
                                      destination_address: str,
                                      amount: Decimal,
                                      sequence=None) -> Tuple[bytes, bytes]:
    """"Build transaction return unsigned XDR and transaction hash.

        Args:
            transaction_source_address: Owner of the transactoin
            source_address: Owner of creator wallet
            destination_address: wallet id of new wallet
            amount: starting balance of new wallet
    """

    builder = Builder(
        address=transaction_source_address,
        horizon=settings['HORIZON_URL'],
        network=settings['PASSPHRASE'],
        sequence=sequence,
    )

    try:
        builder.append_create_account_op(source=source_address,
                                         destination=destination_address,
                                         starting_balance=amount)
    except DecodeError:
        raise web.HTTPBadRequest(reason='Parameter values are not valid.')
    except Exception as e:
        msg = str(e)
        raise web.HTTPInternalServerError(reason=msg)

    try:
        unsigned_xdr = builder.gen_xdr()
    except Exception as e:
        raise web.HTTPBadRequest(
            reason='Bad request, Please ensure parameters are valid.')

    tx_hash = builder.te.hash_meta()

    return unsigned_xdr, tx_hash
Exemple #4
0
    def test_builder(self):
        cold_account = self.cold.address().decode()
        hot_account = self.hot.address().decode()

        fund(cold_account)

        cold = Builder(self.cold.seed().decode())

        cold.append_create_account_op(hot_account, 200)

        cold.append_set_options_op(
            inflation_dest=cold_account,
            set_flags=1,
            home_domain='256kw.com',
            master_weight=10,
            low_threshold=5,
        )
        cold.append_trust_op(cold_account, 'BEER', 1000, source=hot_account)
        cold.append_allow_trust_op(hot_account, 'BEER', True)
        # append twice for test
        cold.append_payment_op(hot_account, 50.123, 'BEER', cold_account)
        cold.append_payment_op(hot_account, 50.123, 'BEER', cold_account)

        cold.sign(self.hot.seed().decode())
        try:  # sign twice
            cold.sign(self.hot.seed().decode())
        except SignatureExistError:
            assert True
        except:
            assert False

        cold.sign()
        assert len(cold.te.signatures) == 2
        assert len(cold.ops) == 5

        try:
            response = cold.submit()
            print(response)
        except:
            assert False
    def test_builder(self):
        cold_account = self.cold.address().decode()
        hot_account = self.hot.address().decode()

        fund(cold_account)

        cold = Builder(self.cold.seed().decode())

        cold.append_create_account_op(hot_account, 200)

        cold.append_set_options_op(inflation_dest=cold_account, set_flags=1,
                                   home_domain='256kw.com',master_weight=10,
                                   low_threshold=5,)
        cold.append_trust_op(cold_account, 'BEER', 1000, source=hot_account)
        cold.append_allow_trust_op(hot_account,'BEER', True)
        # append twice for test
        cold.append_payment_op(hot_account, 50.123, 'BEER', cold_account)
        cold.append_payment_op(hot_account, 50.123, 'BEER', cold_account)

        cold.sign(self.hot.seed().decode())
        try:  # sign twice
            cold.sign(self.hot.seed().decode())
        except SignatureExistError:
            assert True 
        except:
            assert False

        cold.sign()
        assert len(cold.te.signatures) == 2
        assert len(cold.ops) == 5

        try:
            response = cold.submit()
            print(response)
        except:
            assert False
def create_stellar_deposit(transaction_id):
    """Create and submit the Stellar transaction for the deposit."""
    transaction = Transaction.objects.get(id=transaction_id)

    # We check the Transaction status to avoid double submission of a Stellar
    # transaction. The Transaction can be either `pending_anchor` if the task
    # is called from `GET deposit/confirm_transaction` or `pending_trust` if called
    # from the `check_trustlines()`.
    if transaction.status not in [
            Transaction.STATUS.pending_anchor,
            Transaction.STATUS.pending_trust,
    ]:
        return
    transaction.status = Transaction.STATUS.pending_stellar
    transaction.save()

    # We can assume transaction has valid stellar_account, amount_in, and asset
    # because this task is only called after those parameters are validated.
    stellar_account = transaction.stellar_account
    payment_amount = round(transaction.amount_in - transaction.amount_fee, 7)
    asset = transaction.asset.name

    # If the given Stellar account does not exist, create
    # the account with at least enough XLM for the minimum
    # reserve and a trust line (recommended 2.01 XLM), update
    # the transaction in our internal database, and return.

    address = Address(
        stellar_account,
        network=settings.STELLAR_NETWORK,
        horizon_uri=settings.HORIZON_URI,
    )
    try:
        address.get()
    except HorizonError as address_exc:
        # 404 code corresponds to Resource Missing.
        if address_exc.status_code != 404:
            return
        starting_balance = settings.ACCOUNT_STARTING_BALANCE
        builder = Builder(
            secret=settings.STELLAR_ACCOUNT_SEED,
            horizon_uri=settings.HORIZON_URI,
            network=settings.STELLAR_NETWORK,
        )
        builder.append_create_account_op(
            destination=stellar_account,
            starting_balance=starting_balance,
            source=settings.STELLAR_ACCOUNT_ADDRESS,
        )
        builder.sign()
        try:
            builder.submit()
        except HorizonError:
            return
        transaction.status = Transaction.STATUS.pending_trust
        transaction.save()
        return

    # If the account does exist, deposit the desired amount of the given
    # asset via a Stellar payment. If that payment succeeds, we update the
    # transaction to completed at the current time. If it fails due to a
    # trustline error, we update the database accordingly. Else, we do not update.

    builder = Builder(
        secret=settings.STELLAR_ACCOUNT_SEED,
        horizon_uri=settings.HORIZON_URI,
        network=settings.STELLAR_NETWORK,
    )
    builder.append_payment_op(
        destination=stellar_account,
        asset_code=asset,
        asset_issuer=settings.STELLAR_ACCOUNT_ADDRESS,
        amount=str(payment_amount),
    )
    builder.sign()
    try:
        response = builder.submit()
    # Functional errors at this stage are Horizon errors.
    except HorizonError as exception:
        if TRUSTLINE_FAILURE_XDR not in exception.message:
            return
        transaction.status = Transaction.STATUS.pending_trust
        transaction.save()
        return

    # If this condition is met, the Stellar payment succeeded, so we
    # can mark the transaction as completed.
    if response["result_xdr"] != SUCCESS_XDR:
        return

    transaction.stellar_transaction_id = response["hash"]
    transaction.status = Transaction.STATUS.completed
    transaction.completed_at = now()
    transaction.status_eta = 0  # No more status change.
    transaction.amount_out = payment_amount
    transaction.save()
async def build_generate_escrow_wallet_transaction(
    escrow_address: str,
    transaction_source_address: str,
    creator_address: str,
    destination_address: str,
    provider_address: str,
    cost_per_transaction: Decimal,
    starting_native_asset: Decimal,
    starting_custom_asset: Decimal,
    expiration_date: str = None,
    sequence: str = None,
) -> Tuple[Any, str]:
    '''Building transaction for generating escrow wallet with minimum balance of lumens
        and return unsigned XDR and transaction hash.

        Args:

        * escrow_address: an address of new wallet
        * destination_address: an address of wallet which is target
        * transaction_source_address an address from wallet pool
        * provider_address: an address which provides custom_asset to new wallet
        * creator_address: an address of source wallet which is owner of the transaction.
        * cost_per_transaction: cost for each promotion deals.
        * starting_native_asset: starting amount of XLM.
        * starting_custom_asset: starting amount of custom asset(HOT).
        * expiration_date: a date when escrow address is terminated.
    '''

    builder = Builder(
        address=transaction_source_address,
        horizon=settings['HORIZON_URL'],
        network=settings['PASSPHRASE'],
        sequence=sequence,
    )
    builder.append_create_account_op(source=creator_address,
                                     destination=escrow_address,
                                     starting_balance=starting_native_asset)

    try:
        builder.append_trust_op(
            source=escrow_address,
            destination=settings['ISSUER'],
            code=settings['ASSET_CODE'],
            limit=settings['LIMIT_ASSET'],
        )
    except DecodeError:
        raise web.HTTPBadRequest(
            reason='Parameter escrow_address or issuer address are not valid.')
    except Exception as e:
        msg = str(e)
        raise web.HTTPInternalServerError(reason=msg)

    builder.append_manage_data_op(source=escrow_address,
                                  data_name='creator_address',
                                  data_value=creator_address)
    builder.append_manage_data_op(source=escrow_address,
                                  data_name='destination_address',
                                  data_value=destination_address)
    builder.append_manage_data_op(source=escrow_address,
                                  data_name='provider_address',
                                  data_value=provider_address)

    if expiration_date:
        builder.append_manage_data_op(source=escrow_address,
                                      data_name='expiration_date',
                                      data_value=expiration_date)
    builder.append_manage_data_op(source=escrow_address,
                                  data_name='cost_per_transaction',
                                  data_value=str(cost_per_transaction))

    builder.append_set_options_op(source=escrow_address,
                                  signer_address=creator_address,
                                  signer_type='ed25519PublicKey',
                                  signer_weight=1)
    builder.append_set_options_op(source=escrow_address,
                                  signer_address=provider_address,
                                  signer_type='ed25519PublicKey',
                                  signer_weight=1)
    builder.append_set_options_op(source=escrow_address,
                                  master_weight=0,
                                  low_threshold=2,
                                  med_threshold=2,
                                  high_threshold=2)

    builder.append_payment_op(
        source=provider_address,
        destination=escrow_address,
        asset_code=settings['ASSET_CODE'],
        asset_issuer=settings['ISSUER'],
        amount=starting_custom_asset,
    )

    try:
        xdr = builder.gen_xdr()
    except Exception as e:
        raise web.HTTPBadRequest(
            reason='Bad request, Please ensure parameters are valid.')

    tx_hash = builder.te.hash_meta()

    return xdr.decode(), binascii.hexlify(tx_hash).decode()
Exemple #8
0
horizon = horizon_testnet()

print('Initializing keypairs')
kp_alice = initialize_keypair()
kp_bob = initialize_keypair()
kp_carol = initialize_keypair()

print('Carol creates accounts a_1 and a_2')
kp_a_1 = initialize_keypair(add_funds=False)
kp_a_2 = initialize_keypair(add_funds=False)
kp_a_1_address = kp_a_1.address().decode()
kp_a_2_address = kp_a_2.address().decode()
kp_a_1_seed = kp_a_1.seed().decode()
kp_a_2_seed = kp_a_2.seed().decode()
accounts_builder = Builder(secret=kp_carol.seed().decode())
accounts_builder.append_create_account_op(
    kp_a_1_address, '202.50009')
accounts_builder.append_create_account_op(
    kp_a_2_address, '202.50009')
accounts_builder.sign()
response = accounts_builder.submit()
assert 'hash' in response

print('Initializing transactions')
address_a_1 = Address(address=kp_a_1_address)
address_a_2 = Address(address=kp_a_2_address)
address_a_1.get()
address_a_2.get()

starting_sequence_a_1 = int(address_a_1.sequence)
starting_sequence_a_2 = int(address_a_2.sequence)
class Interface:
    """
    Interface to handle all API calls to third-party account.
    """
    def __init__(self, account):
        self.account = account
        if account.secret:
            self.builder = Builder(secret=account.secret,
                                   network=account.network)
        self.address = Address(address=account.account_id,
                               network=account.network)

    def _get_new_receives(self):
        # Get all stored transactions for account
        transactions = ReceiveTransaction.filter(admin_account=self.account)

        # Set the cursor according to latest stored transaction:
        if not transactions:
            cursor = None
        else:
            cursor = int(transactions.latest().data['paging_token']) + 1

        # Get new transactions from the stellar network:
        new_transactions = self._get_receives(cursor=cursor)

        return new_transactions

    def _get_receives(self, cursor=None):
        # If cursor was specified, get all transactions after the cursor:
        if cursor:
            transactions = self.address.payments(cursor=cursor)['_embedded']['records']
            print(transactions)
            for i, tx in enumerate(transactions):
                if tx.get('to') != self.account.account_id:
                    transactions.pop(i)  # remove sends

        # else just get all the transactions:
        else:
            transactions = self.address.payments()['_embedded']['records']
            for i, tx in enumerate(transactions):
                if tx.get('from') == self.account.account_id:
                    transactions.pop(i)  # remove sends

        return transactions

    def _process_receive(self, tx):
        # Get memo:
        details = requests.get(url=tx['_links']['transaction']['href']).json()
        memo = details.get('memo')
        print('memo: ' + str(memo))
        if memo:
            account_id = memo + '*rehive.com'
            user_account = UserAccount.objects.get(account_id=account_id)
            user_email = user_account.user_id  # for this implementation, user_id is the user's email
            amount = to_cents(Decimal(tx['amount']), 7)

            if tx['asset_type'] == 'native':
                currency = 'XLM'
                issuer = ''
            else:
                currency = tx['asset_code']
                issuer_address = tx['asset_issuer']
                issuer = Asset.objects.get(account_id=issuer_address, code=currency).issuer

            # Create Transaction:
            tx = ReceiveTransaction.objects.create(user_account=user_account,
                                                   external_id=tx['hash'],
                                                   recipient=user_email,
                                                   amount=amount,
                                                   currency=currency,
                                                   issuer=issuer,
                                                   status='Waiting',
                                                   data=tx,
                                                   metadata={'type': 'stellar'}
                                                   )

            # TODO: Move tx.upload_to_rehive() to a signal to auto-run after Transaction creation.
            tx.upload_to_rehive()

            return True

    @staticmethod
    def _is_valid_address(address: str) -> bool:
        # TODO: Replace with real address check.
        if len(address) == 56 and '*' not in address:
            return True
        else:
            return False

    # This function should always be included if transactions are received to admin account and not added via webhooks:
    def process_receives(self):
        # Get new receive transactions
        new_transactions = self._get_new_receives()

        # Add each transaction to Rehive and log in transaction table:
        for tx in new_transactions:
            self._process_receive(tx)

    # This function should always be included.
    def process_send(self, tx):
        if self._is_valid_address(tx.recipient):
            address = tx.recipient
        else:
            federation = get_federation_details(tx.recipient)
            if federation['memo_type'] == 'text':
                self.builder.add_text_memo(federation['memo'])
            elif federation['memo_type'] == 'id':
                self.builder.add_id_memo(federation['memo'])
            elif federation['memo_type'] == 'hash':
                self.builder.add_hash_memo(federation['memo'])
            else:
                raise NotImplementedAPIError('Invalid memo type specified.')

            address = federation['account_id']

        # Create account or create payment:
        if tx.currency == 'XLM':
            try:
                address_obj = self.address
                address_obj.get()
                self.builder.append_payment_op(address, tx.amount, 'XLM')
            except APIException as exc:
                if exc.status_code == 404:
                    self.builder.append_create_account_op(address, tx.amount)
        else:
            # Get issuer address details:
            issuer_address = get_issuer_address(tx.issuer, tx.currency)

            address_obj = self.address
            address_obj.get()
            self.builder.append_payment_op(address, tx.amount, tx.currency, issuer_address)

        try:
            self.builder.sign()
            self.builder.submit()
        except Exception as exc:
            print(exc.payload)

    def get_balance(self):
        address = self.address
        address.get()
        for balance in address.balances:
            if balance['asset_type'] == 'native':
                return to_cents(Decimal(balance['balance']), 7)

    def get_issuer_address(self, issuer, asset_code):
        if self._is_valid_address(issuer):
            address = issuer
        else:
            if '*' in issuer:
                address = get_federation_details(issuer)['account_id']
            else:  # assume it is an anchor domain
                address = address_from_domain(issuer, asset_code)

        return address

    def trust_issuer(self, asset_code, issuer):
        logger.info('Trusting issuer: %s %s' % (issuer, asset_code))
        address = self.get_issuer_address(issuer, asset_code)
        self.builder.append_trust_op(address, asset_code)

        try:
            self.builder.sign()
            self.builder.submit()
        except Exception as exc:
            print(exc.payload)

    # Generate new crypto address/ account id
    @staticmethod
    def new_account_id(**kwargs):
        metadata = kwargs.get('metadata')
        account_id = metadata['username'] + '*' + getattr(settings, 'STELLAR_WALLET_DOMAIN')
        return account_id

    def get_account_details(self):
        address = self.account.account_id
        qr_code = create_qr_code_url('stellar:' + str(address))
        return {'account_id': address, 'metadata': {'qr_code': qr_code}}
Exemple #10
0
async def build_joint_wallet(
    transaction_source_address: str,
    deal_address: str,
    parties: List,
    creator: str,
    starting_xlm: Decimal,
    meta: str = None,
    sequence: str = None,
):
    """Build transaction for create joint wallet, trust HOT and set option signer."""
    def _add_signer(builder: Builder, deal_address: str, party: str,
                    amount: Decimal):
        """Set permission of parties can signed transaction that generate from joint account"""
        builder.append_set_options_op(source=deal_address,
                                      signer_address=party,
                                      signer_type='ed25519PublicKey',
                                      signer_weight=1)
        builder.append_payment_op(
            source=party,
            destination=deal_address,
            asset_code=settings['ASSET_CODE'],
            asset_issuer=settings['ISSUER'],
            amount=amount,
        )

    builder = Builder(
        address=transaction_source_address,
        horizon=settings['HORIZON_URL'],
        network=settings['PASSPHRASE'],
        sequence=sequence,
    )
    builder.append_create_account_op(source=creator,
                                     destination=deal_address,
                                     starting_balance=starting_xlm)
    builder.append_trust_op(source=deal_address,
                            destination=settings['ISSUER'],
                            code=settings['ASSET_CODE'],
                            limit=settings['LIMIT_ASSET'])
    builder.append_set_options_op(source=deal_address,
                                  signer_address=creator,
                                  signer_type='ed25519PublicKey',
                                  signer_weight=1)

    for party in parties:
        _add_signer(builder, deal_address, party['address'], party['amount'])

    if meta and isinstance(meta, dict):
        for key, value in meta.items():
            builder.append_manage_data_op(source=deal_address,
                                          data_name=key,
                                          data_value=value)

    builder.append_manage_data_op(source=deal_address,
                                  data_name='creator_address',
                                  data_value=creator)

    weight = len(parties) + 1
    builder.append_set_options_op(source=deal_address,
                                  master_weight=0,
                                  low_threshold=weight,
                                  med_threshold=weight,
                                  high_threshold=weight)
    xdr = builder.gen_xdr()
    tx_hash = builder.te.hash_meta()

    return xdr.decode(), binascii.hexlify(tx_hash).decode()