def test_create_from_invalid_public_key_raise(self, invalid_public_key): with pytest.raises( Ed25519PublicKeyInvalidError, match="Invalid Ed25519 Public Key: {}".format( invalid_public_key), ): Keypair.from_public_key(invalid_public_key)
def deposit(account: str, request: Request) -> Response: """ POST /transactions/deposit/interactive Creates an `incomplete` deposit Transaction object in the database and returns the URL entry-point for the interactive flow. """ asset_code = request.POST.get("asset_code") stellar_account = request.POST.get("account") lang = request.POST.get("lang") if lang: err_resp = validate_language(lang) if err_resp: return err_resp activate_lang_for_request(lang) # Verify that the request is valid. if not all([asset_code, stellar_account]): return render_error_response( _("`asset_code` and `account` are required parameters") ) # Verify that the asset code exists in our database, with deposit enabled. asset = Asset.objects.filter(code=asset_code).first() if not asset: return render_error_response(_("unknown asset: %s") % asset_code) elif not asset.deposit_enabled: return render_error_response(_("invalid operation for asset %s") % asset_code) try: Keypair.from_public_key(stellar_account) except Ed25519PublicKeyInvalidError: return render_error_response(_("invalid 'account'")) # Construct interactive deposit pop-up URL. transaction_id = create_transaction_id() Transaction.objects.create( id=transaction_id, stellar_account=account, asset=asset, kind=Transaction.KIND.deposit, status=Transaction.STATUS.incomplete, to_address=account, ) logger.info(f"Created deposit transaction {transaction_id}") url = interactive_url( request, str(transaction_id), stellar_account, asset_code, settings.OPERATION_DEPOSIT, ) return Response( {"type": "interactive_customer_info_needed", "url": url, "id": transaction_id}, status=status.HTTP_200_OK, )
def deposit(account: str, request: Request) -> Response: """ `POST /transactions/deposit/interactive` initiates the deposit and returns an interactive deposit form to the user. """ asset_code = request.POST.get("asset_code") stellar_account = request.POST.get("account") # Verify that the request is valid. if not all([asset_code, stellar_account]): return render_error_response( "`asset_code` and `account` are required parameters") # Verify that the asset code exists in our database, with deposit enabled. asset = Asset.objects.filter(code=asset_code).first() if not asset or not asset.deposit_enabled: return render_error_response( f"invalid operation for asset {asset_code}") try: Keypair.from_public_key(stellar_account) except Ed25519PublicKeyInvalidError: return render_error_response("invalid 'account'") # Verify the optional request arguments. verify_optional_args = _verify_optional_args(request) if verify_optional_args: return verify_optional_args # Construct interactive deposit pop-up URL. transaction_id = create_transaction_id() Transaction.objects.create( id=transaction_id, stellar_account=account, asset=asset, kind=Transaction.KIND.deposit, status=Transaction.STATUS.incomplete, to_address=account, ) url = rdi.interactive_url(request, str(transaction_id), stellar_account, asset_code) return Response( { "type": "interactive_customer_info_needed", "url": url, "id": transaction_id }, status=status.HTTP_200_OK, )
def test_auth_get_account(client): """`GET <auth>` succeeds with a valid TransactionEnvelope XDR.""" response = client.get(f"/auth?account={STELLAR_ACCOUNT_1}", follow=True) content = json.loads(response.content) assert content["network_passphrase"] == "Test SDF Network ; September 2015" assert content["transaction"] envelope_xdr = content["transaction"] envelope_object = TransactionEnvelope.from_xdr( envelope_xdr, network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE) transaction_object = envelope_object.transaction assert transaction_object.sequence == 0 assert len(transaction_object.operations) == 1 manage_data_op = transaction_object.operations[0] assert manage_data_op.type_code() == Xdr.const.MANAGE_DATA assert manage_data_op.data_name == "SEP 24 Reference auth" assert len(manage_data_op.data_value) == 64 signatures = envelope_object.signatures assert len(signatures) == 1 server_signature = signatures[0] tx_hash = envelope_object.hash() server_public_key = Keypair.from_public_key( settings.STELLAR_DISTRIBUTION_ACCOUNT_ADDRESS) server_public_key.verify(tx_hash, server_signature.signature)
def test_auth_get_account(client): """`GET <auth>` succeeds with a valid TransactionEnvelope XDR.""" response = client.get(f"{endpoint}?account={STELLAR_ACCOUNT_1}", follow=True) content = json.loads(response.content) assert content["network_passphrase"] == "Test SDF Network ; September 2015" assert content["transaction"] envelope_xdr = content["transaction"] envelope_object = TransactionEnvelope.from_xdr( envelope_xdr, network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE) transaction_object = envelope_object.transaction assert transaction_object.sequence == 0 assert len(transaction_object.operations) == 1 manage_data_op = transaction_object.operations[0] assert manage_data_op.type_code() == Xdr.const.MANAGE_DATA assert manage_data_op.data_name == f"{urlparse(settings.HOST_URL).netloc} auth" assert len(manage_data_op.data_value) <= 64 assert len(base64.b64decode(manage_data_op.data_value)) == 48 signatures = envelope_object.signatures assert len(signatures) == 1 server_signature = signatures[0] tx_hash = envelope_object.hash() server_public_key = Keypair.from_public_key(settings.SIGNING_KEY) server_public_key.verify(tx_hash, server_signature.signature)
def test_auth_get_success(client): """`GET <auth>` succeeds with a valid TransactionEnvelope XDR.""" response = client.get(f"{endpoint}?account={STELLAR_ACCOUNT_1}", follow=True) content = json.loads(response.content) assert content["network_passphrase"] == "Test SDF Network ; September 2015" assert content["transaction"] envelope_xdr = content["transaction"] envelope_object = TransactionEnvelope.from_xdr( envelope_xdr, network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE) transaction_object = envelope_object.transaction assert transaction_object.sequence == 0 assert len(transaction_object.operations) == 2 home_domain_op = transaction_object.operations[0] assert isinstance(home_domain_op, ManageData) assert home_domain_op.data_name == f"{urlparse(settings.HOST_URL).netloc} auth" assert len(home_domain_op.data_value) <= 64 assert len(base64.b64decode(home_domain_op.data_value)) == 48 web_auth_domain_op = transaction_object.operations[1] assert isinstance(web_auth_domain_op, ManageData) assert web_auth_domain_op.data_name == "web_auth_domain" assert (web_auth_domain_op.data_value == f"{urlparse(settings.HOST_URL).netloc}".encode()) signatures = envelope_object.signatures assert len(signatures) == 1 tx_hash = envelope_object.hash() server_public_key = Keypair.from_public_key(settings.SIGNING_KEY) server_public_key.verify(tx_hash, signatures[0].signature)
def test_can_sign(self): can_sign_kp = Keypair.from_secret( "SD7X7LEHBNMUIKQGKPARG5TDJNBHKC346OUARHGZL5ITC6IJPXHILY36") can_not_sign_kp = Keypair.from_public_key( "GAXDYNIBA5E4DXR5TJN522RRYESFQ5UNUXHIPTFGVLLD5O5K552DF5ZH") assert can_sign_kp.can_sign() is True assert can_not_sign_kp.can_sign() is False
def create_stellar_deposit(transaction: Transaction) -> bool: """ Performs final status and signature checks before calling submit_stellar_deposit(). Returns true on successful submission, false otherwise. `transaction` will be placed in the error status if submission fails or if it is a multisig transaction and is not signed by the channel account. """ if transaction.status not in [ Transaction.STATUS.pending_anchor, Transaction.STATUS.pending_trust, ]: raise ValueError( f"unexpected transaction status {transaction.status} for " "create_stellar_deposit", ) elif transaction.amount_in is None or transaction.amount_fee is None: transaction.status = Transaction.STATUS.error transaction.status_message = ( "`amount_in` and `amount_fee` must be populated, skipping transaction" ) transaction.save() raise ValueError(transaction.status_message) # if the distribution account's master signer's weight is great or equal to the its # medium threshold, verify the transaction is signed by it's channel account master_signer = None if transaction.asset.distribution_account_master_signer: master_signer = transaction.asset.distribution_account_master_signer thresholds = transaction.asset.distribution_account_thresholds if not master_signer or master_signer["weight"] < thresholds[ "med_threshold"]: envelope = TransactionEnvelope.from_xdr( transaction.envelope_xdr, settings.STELLAR_NETWORK_PASSPHRASE) try: _verify_te_signed_by_account_id(envelope, transaction.channel_account) except InvalidSep10ChallengeError: transaction.status = Transaction.STATUS.error transaction.status_message = gettext( "Multisig transaction's envelope was not signed by channel account" ) transaction.save() return False # otherwise, create the envelope and sign it with the distribution account's secret else: distribution_acc, _ = get_account_obj( Keypair.from_public_key(transaction.asset.distribution_account)) envelope = create_transaction_envelope(transaction, distribution_acc) envelope.sign(transaction.asset.distribution_seed) try: submit_stellar_deposit(transaction, envelope) except (RuntimeError, BaseHorizonError) as e: transaction.status_message = f"{e.__class__.__name__}: {e.message}" transaction.status = Transaction.STATUS.error transaction.save() logger.error(transaction.status_message) return False else: return True
def test_create_from_public_key(self): public_key = "GAXDYNIBA5E4DXR5TJN522RRYESFQ5UNUXHIPTFGVLLD5O5K552DF5ZH" kp = Keypair.from_public_key(public_key) assert isinstance(kp, Keypair) assert (kp.public_key == "GAXDYNIBA5E4DXR5TJN522RRYESFQ5UNUXHIPTFGVLLD5O5K552DF5ZH") assert ( kp.raw_public_key().hex() == "2e3c35010749c1de3d9a5bdd6a31c12458768da5ce87cca6aad63ebbaaef7432")
def deposit(request): """ `GET /deposit` initiates the deposit and returns an interactive deposit form to the user. """ asset_code = request.GET.get("asset_code") stellar_account = request.GET.get("account") # Verify that the request is valid. if not all([asset_code, stellar_account]): return render_error_response( "`asset_code` and `account` are required parameters") # Verify that the asset code exists in our database, with deposit enabled. asset = Asset.objects.filter(code=asset_code).first() if not asset or not asset.deposit_enabled: return render_error_response( f"invalid operation for asset {asset_code}") try: Keypair.from_public_key(stellar_account) except Ed25519PublicKeyInvalidError: return render_error_response("invalid 'account'") # Verify the optional request arguments. verify_optional_args = _verify_optional_args(request) if verify_optional_args: return verify_optional_args # Construct interactive deposit pop-up URL. transaction_id = create_transaction_id() url = _construct_interactive_url(request, transaction_id) return Response( { "type": "interactive_customer_info_needed", "url": url, "id": transaction_id }, status=status.HTTP_403_FORBIDDEN, )
def test_from_xdr_object_alphanum12(self): code = "Banana" issuer = "GCNY5OXYSY4FKHOPT2SPOQZAOEIGXB5LBYW3HVU3OWSTQITS65M5RCNY" type = "credit_alphanum12" x = Xdr.nullclass() x.assetCode = bytearray(code, "ascii") + b"\x00" * 6 x.issuer = Keypair.from_public_key(issuer).xdr_account_id() xdr_type = Xdr.const.ASSET_TYPE_CREDIT_ALPHANUM12 xdr = Xdr.types.Asset(type=xdr_type, alphaNum12=x) asset = Asset.from_xdr_object(xdr) assert asset.code == code assert asset.issuer == issuer assert asset.type == type
def test_from_xdr_object_alphanum12(self): code = "Banana" issuer = "GCNY5OXYSY4FKHOPT2SPOQZAOEIGXB5LBYW3HVU3OWSTQITS65M5RCNY" type = "credit_alphanum12" asset_code = stellar_xdr.AssetCode12( bytearray(code, "ascii") + b"\x00" * (12 - len(code))) asset = stellar_xdr.AssetAlphaNum12( asset_code=asset_code, issuer=Keypair.from_public_key(issuer).xdr_account_id(), ) xdr = stellar_xdr.Asset( type=stellar_xdr.AssetType.ASSET_TYPE_CREDIT_ALPHANUM12, alpha_num12=asset) asset = Asset.from_xdr_object(xdr) assert asset.code == code assert asset.issuer == issuer assert asset.type == type
def create_transaction_envelope(transaction, source_account) -> TransactionEnvelope: payment_amount = round( Decimal(transaction.amount_in) - Decimal(transaction.amount_fee), transaction.asset.significant_decimals, ) memo = make_memo(transaction.memo, transaction.memo_type) builder = TransactionBuilder( source_account=source_account, network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE, # only one operation, so base_fee will be multipled by 1 base_fee=settings.MAX_TRANSACTION_FEE_STROOPS or settings.HORIZON_SERVER.fetch_base_fee(), ) _, json_resp = get_account_obj( Keypair.from_public_key(transaction.stellar_account)) if transaction.claimable_balance_supported and is_pending_trust( transaction, json_resp): logger.debug( f"Crafting claimable balance operation for Transaction {transaction.id}" ) claimant = Claimant(destination=transaction.stellar_account) asset = Asset(code=transaction.asset.code, issuer=transaction.asset.issuer) builder.append_create_claimable_balance_op( claimants=[claimant], asset=asset, amount=str(payment_amount), source=transaction.asset.distribution_account, ) else: builder.append_payment_op( destination=transaction.stellar_account, asset_code=transaction.asset.code, asset_issuer=transaction.asset.issuer, amount=str(payment_amount), source=transaction.asset.distribution_account, ) if memo: builder.add_memo(memo) return builder.build()
def handle_bad_signatures_error(e, transaction, multisig=False): err_msg = (f"Horizon returned a {e.__class__.__name__} on transaction " f"{transaction.id} submission.") logger.error(err_msg) logger.error( f"Transaction {transaction.id} envelope XDR: {transaction.envelope_xdr}" ) logger.error(f"Transaction {transaction.id} result XDR: {e.result_xdr}") if multisig: logger.error( f"Resetting the Transaction.envelope_xdr for {transaction.id}, " "updating Transaction.pending_signatures to True") channel_account, _ = get_account_obj( Keypair.from_public_key(transaction.channel_account)) transaction.envelope_xdr = create_transaction_envelope( transaction, channel_account).to_xdr() transaction.pending_signatures = True transaction.status = Transaction.STATUS.pending_anchor = True else: transaction.status = Transaction.STATUS.error transaction.status_message = ( f"Horizon returned a {e.__class__.__name__} on transaction " f"{transaction.id} submission") transaction.save()
def create_stellar_deposit(transaction: Transaction, destination_exists: bool = False) -> bool: """ Create and submit the Stellar transaction for the deposit. The Transaction can be either `pending_anchor` if the task is called from `poll_pending_deposits()` or `pending_trust` if called from the `check_trustlines()`. """ if transaction.status not in [ Transaction.STATUS.pending_anchor, Transaction.STATUS.pending_trust, ]: raise ValueError( f"unexpected transaction status {transaction.status} for " "create_stellar_deposit", ) elif transaction.amount_in is None or transaction.amount_fee is None: transaction.status = Transaction.STATUS.error transaction.status_message = ( "`amount_in` and `amount_fee` must be populated, skipping transaction" ) transaction.save() raise ValueError(transaction.status_message) # if we don't know if the destination account exists if not destination_exists: try: _, created, pending_trust = get_or_create_transaction_destination_account( transaction) except RuntimeError as e: transaction.status = Transaction.STATUS.error transaction.status_message = str(e) transaction.save() logger.error(transaction.status_message) return False if created or pending_trust: # the account is pending_trust for the asset to be received if pending_trust and transaction.status != Transaction.STATUS.pending_trust: transaction.status = Transaction.STATUS.pending_trust transaction.save() return False # if the distribution account's master signer's weight is great or equal to the its # medium threshold, verify the transaction is signed by it's channel account master_signer = None if transaction.asset.distribution_account_master_signer: master_signer = transaction.asset.distribution_account_master_signer thresholds = transaction.asset.distribution_account_thresholds if not (master_signer and master_signer["weight"] >= thresholds["med_threshold"]): multisig = True envelope = TransactionEnvelope.from_xdr( transaction.envelope_xdr, settings.STELLAR_NETWORK_PASSPHRASE) try: _verify_te_signed_by_account_id(envelope, transaction.channel_account) except InvalidSep10ChallengeError: transaction.status = Transaction.STATUS.error transaction.status_message = gettext( "Multisig transaction's envelope was not signed by channel account" ) transaction.save() return False # otherwise, create the envelope and sign it with the distribution account's secret else: multisig = False distribution_acc, _ = get_account_obj( Keypair.from_public_key(transaction.asset.distribution_account)) envelope = create_transaction_envelope(transaction, distribution_acc) envelope.sign(transaction.asset.distribution_seed) transaction.envelope_xdr = envelope.to_xdr() try: return submit_stellar_deposit(transaction, multisig=multisig) except RuntimeError as e: transaction.status_message = str(e) transaction.status = Transaction.STATUS.error transaction.save() logger.error(transaction.status_message) return False
"source": "GCUZ6YLL5RQBTYLTTQLPCM73C5XAIUGK2TIMWQH7HPSGWVS2KJ2F3CHS", "paging_token": "123456789", } mock_envelope = Mock(transaction=Mock( operations=[ Mock( asset=Mock( issuer=USD_ISSUER_ACCOUNT, code="USD", ), amount=50, destination=Keypair.from_secret(USD_DISTRIBUTION_SEED).public_key, type_code=Mock(return_value=1), ) ], source=Keypair.from_public_key( "GCUZ6YLL5RQBTYLTTQLPCM73C5XAIUGK2TIMWQH7HPSGWVS2KJ2F3CHS"), )) @pytest.mark.django_db @patch(f"{test_module}.TransactionEnvelope.from_xdr", return_value=mock_envelope) def test_process_response_success(mock_xdr, client, acc1_usd_withdrawal_transaction_factory): del mock_xdr mock_source_account = mock_envelope.transaction.source.public_key transaction = acc1_usd_withdrawal_transaction_factory(mock_source_account) json = deepcopy(TRANSACTION_JSON) json["successful"] = True json["id"] = transaction.id json["memo"] = transaction.memo
def deposit(account: str, client_domain: Optional[str], request: Request) -> Response: """ POST /transactions/deposit/interactive Creates an `incomplete` deposit Transaction object in the database and returns the URL entry-point for the interactive flow. """ asset_code = request.data.get("asset_code") stellar_account = request.data.get("account") lang = request.data.get("lang") sep9_fields = extract_sep9_fields(request.data) claimable_balance_supported = request.data.get( "claimable_balance_supported") if not claimable_balance_supported: claimable_balance_supported = False elif isinstance(claimable_balance_supported, str): if claimable_balance_supported.lower() not in ["true", "false"]: return render_error_response( _("'claimable_balance_supported' value must be 'true' or 'false'" )) claimable_balance_supported = claimable_balance_supported.lower( ) == "true" elif not isinstance(claimable_balance_supported, bool): return render_error_response( _("unexpected data type for 'claimable_balance_supprted'. Expected string or boolean." )) if lang: err_resp = validate_language(lang) if err_resp: return err_resp activate_lang_for_request(lang) # Verify that the request is valid. if not all([asset_code, stellar_account]): return render_error_response( _("`asset_code` and `account` are required parameters")) # Ensure memo won't cause stellar transaction to fail when submitted try: make_memo(request.data.get("memo"), request.data.get("memo_type")) except ValueError: return render_error_response(_("invalid 'memo' for 'memo_type'")) # Verify that the asset code exists in our database, with deposit enabled. asset = Asset.objects.filter(code=asset_code).first() if not asset: return render_error_response(_("unknown asset: %s") % asset_code) elif not (asset.deposit_enabled and asset.sep24_enabled): return render_error_response( _("invalid operation for asset %s") % asset_code) amount = None if request.data.get("amount"): try: amount = Decimal(request.data.get("amount")) except DecimalException: return render_error_response(_("invalid 'amount'")) if not (asset.deposit_min_amount <= amount <= asset.deposit_max_amount): return render_error_response(_("invalid 'amount'")) try: Keypair.from_public_key(stellar_account) except Ed25519PublicKeyInvalidError: return render_error_response(_("invalid 'account'")) try: rdi.save_sep9_fields( stellar_account, sep9_fields, lang, ) except ValueError as e: # The anchor found a validation error in the sep-9 fields POSTed by # the wallet. The error string returned should be in the language # specified in the request. return render_error_response(str(e)) # Construct interactive deposit pop-up URL. transaction_id = create_transaction_id() Transaction.objects.create( id=transaction_id, stellar_account=account, asset=asset, kind=Transaction.KIND.deposit, status=Transaction.STATUS.incomplete, to_address=account, protocol=Transaction.PROTOCOL.sep24, claimable_balance_supported=claimable_balance_supported, memo=request.data.get("memo"), memo_type=request.data.get("memo_type") or Transaction.MEMO_TYPES.hash, more_info_url=request.build_absolute_uri( f"{reverse('more_info')}?id={transaction_id}"), client_domain=client_domain, ) logger.info(f"Created deposit transaction {transaction_id}") url = interactive_url( request, str(transaction_id), account, asset_code, settings.OPERATION_DEPOSIT, amount, ) return Response( { "type": "interactive_customer_info_needed", "url": url, "id": transaction_id }, status=status.HTTP_200_OK, )
def deposit(account: str, request: Request) -> Response: """ POST /transactions/deposit/interactive Creates an `incomplete` deposit Transaction object in the database and returns the URL entry-point for the interactive flow. """ asset_code = request.POST.get("asset_code") stellar_account = request.POST.get("account") lang = request.POST.get("lang") sep9_fields = extract_sep9_fields(request.POST) if lang: err_resp = validate_language(lang) if err_resp: return err_resp activate_lang_for_request(lang) # Verify that the request is valid. if not all([asset_code, stellar_account]): return render_error_response( _("`asset_code` and `account` are required parameters")) # Ensure memo won't cause stellar transaction to fail when submitted try: memo = memo_str(request.POST.get("memo"), request.POST.get("memo_type")) except ValueError: return render_error_response(_("invalid 'memo' for 'memo_type'")) amount = None if request.POST.get("amount"): try: amount = Decimal(request.POST.get("amount")) except DecimalException as e: return render_error_response(_("Invalid 'amount'")) # Verify that the asset code exists in our database, with deposit enabled. asset = Asset.objects.filter(code=asset_code).first() if not asset: return render_error_response(_("unknown asset: %s") % asset_code) elif not (asset.deposit_enabled and asset.sep24_enabled): return render_error_response( _("invalid operation for asset %s") % asset_code) try: Keypair.from_public_key(stellar_account) except Ed25519PublicKeyInvalidError: return render_error_response(_("invalid 'account'")) try: rdi.save_sep9_fields(stellar_account, sep9_fields, lang) except ValueError as e: # The anchor found a validation error in the sep-9 fields POSTed by # the wallet. The error string returned should be in the language # specified in the request. return render_error_response(str(e)) # Construct interactive deposit pop-up URL. transaction_id = create_transaction_id() Transaction.objects.create( id=transaction_id, stellar_account=account, asset=asset, kind=Transaction.KIND.deposit, status=Transaction.STATUS.incomplete, to_address=account, protocol=Transaction.PROTOCOL.sep24, memo=memo, memo_type=request.POST.get("memo_type") or Transaction.MEMO_TYPES.hash, ) logger.info(f"Created deposit transaction {transaction_id}") url = interactive_url( request, str(transaction_id), account, asset_code, settings.OPERATION_DEPOSIT, amount, ) return Response( { "type": "interactive_customer_info_needed", "url": url, "id": transaction_id }, status=status.HTTP_200_OK, )
def test_sign_without_secret_raise(self): data = b"Hello, Stellar!" can_not_sign_kp = Keypair.from_public_key( "GAXDYNIBA5E4DXR5TJN522RRYESFQ5UNUXHIPTFGVLLD5O5K552DF5ZH") with pytest.raises(MissingEd25519SecretSeedError): can_not_sign_kp.sign(data)
def test_read_secret_without_secret_raise(self): kp = Keypair.from_public_key( "GAXDYNIBA5E4DXR5TJN522RRYESFQ5UNUXHIPTFGVLLD5O5K552DF5ZH") with pytest.raises(MissingEd25519SecretSeedError): secret = kp.secret
def get_or_create_transaction_destination_account( transaction, ) -> Tuple[Optional[Account], bool, bool]: """ Returns the stellar_sdk.account.Account for which this transaction's payment will be sent to as as well as whether or not the account was created as a result of calling this function. If the account exists, the function simply returns the account and False. If the account doesn't exist, Polaris must create the account using an account provided by the anchor. Polaris can use the distribution account of the anchored asset or a channel account if the asset's distribution account requires non-master signatures. If the transacted asset's distribution account does not require non-master signatures, Polaris can create the destination account using the distribution account. On successful creation, this function will return the account and True. On failure, a RuntimeError exception is raised. If the transacted asset's distribution account does require non-master signatures, the anchor should save a keypair of a pre-existing Stellar account to use as the channel account via DepositIntegration.create_channel_account(). This channel account must only be used as the source account for transactions related to the ``Transaction`` object passed. It also must not be used to submit transactions by any service other than Polaris. If it is, the outstanding transactions will be invalidated due to bad sequence numbers. Finally, the channel accounts must have a master signer with a weight greater than or equal to the medium threshold for the account. After the transaction for creating the destination account has been submitted to the stellar network and the transaction has been created, this function will return the account and True. If the transaction was not submitted successfully, a RuntimeError exception will be raised. """ try: account, json_resp = get_account_obj( Keypair.from_public_key(transaction.stellar_account)) return account, False, has_trustline(transaction, json_resp) except RuntimeError: master_signer = None if transaction.asset.distribution_account_master_signer: master_signer = transaction.asset.distribution_account_master_signer thresholds = transaction.asset.distribution_account_thresholds if master_signer and master_signer["weight"] >= thresholds[ "med_threshold"]: source_account_kp = Keypair.from_secret( transaction.asset.distribution_seed) source_account, _ = get_account_obj(source_account_kp) else: from polaris.integrations import registered_deposit_integration as rdi rdi.create_channel_account(transaction) source_account_kp = Keypair.from_secret(transaction.channel_seed) source_account, _ = get_account_obj(source_account_kp) base_fee = settings.HORIZON_SERVER.fetch_base_fee() builder = TransactionBuilder( source_account=source_account, network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE, base_fee=base_fee, ) transaction_envelope = builder.append_create_account_op( destination=transaction.stellar_account, starting_balance=settings.ACCOUNT_STARTING_BALANCE, ).build() transaction_envelope.sign(source_account_kp) try: settings.HORIZON_SERVER.submit_transaction(transaction_envelope) except BaseHorizonError as submit_exc: # pragma: no cover raise RuntimeError( "Horizon error when submitting create account to horizon: " f"{submit_exc.message}") transaction.status = Transaction.STATUS.pending_trust transaction.save() logger.info( f"Transaction {transaction.id} is now pending_trust of destination account" ) account, json_resp = get_account_obj( Keypair.from_public_key(transaction.stellar_account)) return account, True, has_trustline(transaction, json_resp) except BaseHorizonError as e: raise RuntimeError( f"Horizon error when loading stellar account: {e.message}")
def test_signature_hint(self, public_key, hint): assert Keypair.from_public_key(public_key).signature_hint() == hint
from stellar_sdk.keypair import Keypair # create a random keypair print("create a random keypair") kp = Keypair.random() print("Secret: {}".format(kp.secret)) print("Public Key: {}".format(kp.public_key)) print("") # create a keypair from secret print("create a keypair from secret") secret = "SBRR6ZPBHHTDXYSFRZR2QZCGDZURNE5ON4M4F3HQA42G3Z62SFCR7EEJ" kp = Keypair.from_secret(secret) print("Secret: {}".format(kp.secret)) print("Public Key: {}".format(kp.public_key)) print("") # create a keypair from public key print("create a keypair from public key") public_key = "GDCZ6JDZMWYORTIHEO2E4ZXKBQ2TLXNRQJPJH5RCFN7Q7I24G4RGLXP6" kp = Keypair.from_public_key(public_key) print("Public Key: {}".format(kp.public_key))
def _is_valid_key(self, public_key): try: Keypair.from_public_key(public_key=public_key) return True except Ed25519PublicKeyInvalidError: raise InvalidStellarAddressException("Invalid stellar address")