Integrations

Polaris does most of the work implementing SEP-24. However, some pieces of SEP-24 can only be implemented by the anchor. Specifically, anchors need to implement their own banking rails and KYC requirements. This is where the Integrations classes come in

These classes should be subclassed and its methods overridden by Polaris developers to fill in the gaps in Polaris’s functionality.

The SDF also maintains an reference implementation of an anchor server using Polaris. The source can be found in the Polaris github repository.

Banking Rails

Polaris simply doesn’t have the information it needs to interface with an anchor’s partner financial entities. That is why Polaris provides a set of integration functions for anchors to override.

polaris.integrations.DepositIntegration.poll_pending_deposits(pending_deposits: django.db.models.query.QuerySet) → List[polaris.models.Transaction]

OVERRIDE REQUIRED

This function should poll the financial entity for the state of all pending_deposits and return the ones that have externally completed.

For every transaction that is returned, Polaris will submit it to the Stellar network. If a transaction was completed on the network, the overridable after_deposit() function will be called, however overriding this function is optional.

If the Stellar network is unable to execute a transaction returned from this function, it’s status will be marked as pending_stellar and its status_message attribute will be assigned a description of the problem that occurred. If the Stellar network is successful, the transaction will be marked as completed.

pending_deposits is a QuerySet of the form

Transactions.object.filter(
    kind=Transaction.KIND.deposit,
    status=Transaction.STATUS.pending_user_transfer_start
)

If you have many pending deposits, you may way want to batch the retrieval of these objects to improve query performance and memory usage.

Parameters:pending_deposits – a django Queryset for pending Transactions
Returns:a list of Transaction database objects which correspond to successful user deposits to the anchor’s account.
polaris.integrations.DepositIntegration.after_deposit(transaction: polaris.models.Transaction)

Use this function to perform any post-processing of transaction after its been executed on the Stellar network. This could include actions such as updating other django models in your project or emailing users about completed deposits. Overriding this function is not required.

Parameters:transaction – a Transaction that was executed on the Stellar network
polaris.integrations.WithdrawalIntegration.process_withdrawal(response: Dict[KT, VT], transaction: polaris.models.Transaction)

OVERRIDE REQUIRED

This method should implement the transfer of the amount of the anchored asset specified by transaction to the user who requested the withdrawal.

If an error is raised from this function, the transaction’s status will be changed to error and its status_message will be assigned to the message raised with the exception.

Parameters:
  • response – a response body returned from Horizon for the transactions for account endpoint
  • transaction – a Transaction instance to process

Form Integrations

Polaris uses Django Forms for collecting users’ information, such as their email or how much of their asset they want to deposit. Polaris comes out of the box with forms for deposit and withdrawal flows.

However, the data collected may not be sufficient for your needs. Maybe you need to collect additional fields and do some validation or processing with the data that Polaris doesn’t already do. Maybe you need to serve more forms than just the one to collect transaction information.

That is why Polaris provides a set of integration functions that allow you to collect, validate, and process the information you need with as many forms as you want. The set of functions documented below outline how Polaris supports a customizable interactive flow.

See the Forms documentation for the TransactionForm definition.

polaris.integrations.DepositIntegration.form_for_transaction(transaction: polaris.models.Transaction) → Optional[Type[django.forms.forms.Form]]

This function should return the next form class to render for the user given the state of the interactive flow.

For example, this function should return a TransactionForm to get the amount that should be transferred. Once the form is submitted, Polaris will detect the form used is a TransactionForm subclass and update the amount_in column with the amount specified in form.

After a form is submitted and validated, Polaris will call DepositlIntegration.after_form_validation() with the populated form and transaction. This is where developers should update their own state-tracking constructs or do any processing with the data submitted in the form.

Finally, Polaris will call this function again to check if there is another form that needs to be rendered to the user. If you are collecting KYC data, return a forms.Form with the fields you need.

This loop of submitting a form, validating & processing it, and checking for the next form will continue until this function returns None.

When that happens, Polaris will update the Transaction status to pending_user_transfer_start. Once the user makes the deposit to the anchor’s bank account, DepositIntegration.poll_pending_deposits() should detect the event, and Polaris will submit the transaction to the stellar network, ultimately marking the transaction as complete upon success.

Parameters:transaction – the Transaction database object
Returns:an uninitialized forms.Form subclass. For transaction information, return a polaris.integrations.TransactionForm subclass.
polaris.integrations.DepositIntegration.after_form_validation(form: django.forms.forms.Form, transaction: polaris.models.Transaction)

Use this function to process the data collected with form and to update the state of the interactive flow so that the next call to DepositIntegration.form_for_transaction() returns the next form to render to the user, or None.

Keep in mind that if a TransactionForm is submitted, Polaris will update the amount_in and amount_fee with the information collected. There is no need to implement that yourself.

DO NOT update transaction.status here or in any other function for that matter. This column is managed by Polaris and is expected to have particular values at different points in the flow.

If you need to store some data to determine which form to return next when DepositIntegration.form_for_transaction() is called, store this data in a model not used by Polaris.

Parameters:
  • form – the completed forms.Form submitted by the user
  • transaction – the Transaction database object
polaris.integrations.WithdrawalIntegration.form_for_transaction(transaction: polaris.models.Transaction) → Optional[Type[django.forms.forms.Form]]

This function should return the next form class to render for the user given the state of the interactive flow.

For example, this function should return a TransactionForm to get the amount that should be transferred. Once the form is submitted, Polaris will detect the form used is a TransactionForm subclass and update the amount_in column with the amount specified in form.

After a form is submitted and validated, Polaris will call WithdrawalIntegration.after_form_validation() with the populated form and transaction. This is where developers should update their own state-tracking constructs or do any processing with the data submitted in the form.

Finally, Polaris will call this function again to check if there is another form that needs to be rendered to the user. If you are collecting KYC data, return a forms.Form with the fields you need.

This loop of submitting a form, validating & processing it, and checking for the next form will continue until this function returns None.

When that happens, Polaris will update the Transaction status to pending_external. Once the wallet submits the withdrawal transaction to the stellar network, Polaris will detect the event and mark the transaction status as complete.

Parameters:transaction – the Transaction database object
Returns:an uninitialized forms.Form subclass. For transaction information, use a TransactionForm subclass.
polaris.integrations.WithdrawalIntegration.after_form_validation(form: polaris.integrations.forms.TransactionForm, transaction: polaris.models.Transaction)

Use this function to process the data collected with form and to update the state of the interactive flow so that the next call to WithdrawalIntegration.form_for_transaction() returns the next form to render to the user, or None.

Keep in mind that if a TransactionForm is submitted, Polaris will update the amount_in and amount_fee with the information collected. There is no need to implement that yourself.

DO NOT update transaction.status here or in any other function for that matter. This column is managed by Polaris and is expected to have particular values at different points in the flow.

If you need to store some data to determine which form to return next when WithdrawalIntegration.form_for_transaction() is called, store this data in a model not used by Polaris.

Parameters:
  • form – the completed forms.Form submitted by the user
  • transaction – the Transaction database object

Form CSS

Polaris uses default CSS provided by Bulma for styling forms. To keep the UX consistent, make sure to pass in a modified widget parameter to all form fields displaying text like so:

widget=forms.widgets.TextInput(attrs={"class": "input"})

The attrs parameter adds a HTML attribute to the <input> tag that Bulma uses to add better styling. You may also add more Bulma-supported attributes to Polaris forms.

Use an External Application for the Interactive Flow

Polaris provides Form Integrations for collecting and processing information about a deposit or withdraw. However if you would rather use another application to collect that information, override this function to return the URL that should be requested to begin that process.

Note that if you choose to use another application or set of endpoints, you must redirect to the /transactions/<deposit or withdraw>/interactive/complete?id= endpoint for the relevant transaction when finished. This signals to the wallet that the anchor is done processing the transaction and may resume control.

polaris.integrations.DepositIntegration.interactive_url(request: rest_framework.request.Request, transaction_id: str, account: str, asset_code: str) → str

Override this function to provide the wallet a non-Polaris endpoint to begin the interactive flow.

Returns:a URL to be used as the entry point for the interactive deposit flow
polaris.integrations.WithdrawalIntegration.interactive_url(request: rest_framework.request.Request, transaction_id: str, account: str, asset_code: str) → str

Override this function to provide the wallet a non-Polaris endpoint to begin the interactive flow.

Returns:a URL to be used as the entry point for the interactive withdraw flow

stellar.toml Integration

Every anchor must define a stellar.toml file to describe the anchors’s supported currencies, any validators that are run, and other meta data. Polaris provides a default function that returns the currency supported by your server, but you’ll almost certainly need to replace this default to provide more detailed information.

polaris.integrations.get_stellar_toml()[source]

Returns the default info for stellar.toml as a dictionary. Replace this function with another by passing it to polaris.integrations.register_integrations() like so:

from myapp.integrations import get_toml_data

register_integrations(
    deposit=DepositIntegration(),
    withdrawal=WithdrawalIntegration(),
    toml_func=get_toml_data
)

The function you pass to the toml_func parameter should return a dictionary containing any of the following top level keys: DOCUMENTATION - CURRENCIES - PRINCIPALS - VALIDATORS

You can also pass other top-level keys defined in the Account Info section such as VERSION, but many of these keys are pre-populated based on the variables defined in your .env file, so this isn’t strictly necessary.

See SEP-1 for more information on the stellar.toml format.

Returns:a dictionary containing the fields defined in SEP-1

Deposit Instructions

polaris.integrations.DepositIntegration.instructions_for_pending_deposit(transaction: polaris.models.Transaction)

For pending deposits, its common to show instructions to the user for how to initiate the external transfer. Use this function to return text or HTML instructions to be rendered in response to /transaction/more_info.

Parameters:transaction – the transaction database object to be serialized and rendered in the response.
Returns:the text or HTML to render in the instructions template section

Registering Integrations

In order for Polaris to use the integration classes you’ve defined, you must register them.

polaris.integrations.register_integrations(deposit: polaris.integrations.transactions.DepositIntegration = None, withdrawal: polaris.integrations.transactions.WithdrawalIntegration = None, toml_func: Callable = None)[source]

Registers instances of user-defined subclasses of WithdrawalIntegration and DepositIntegration with Polaris.

Call this function in the relevant Django AppConfig.ready() function:

from django.apps import AppConfig

class PolarisIntegrationApp(AppConfig):
    name = 'Polaris Integration'
    verbose_name = name

    def ready(self):
        from polaris.integrations import register_integrations
        from myapp.integrations import (MyDepositIntegration,
                                        MyWithdrawalIntegration,
                                        get_toml_data)

        register_integrations(
            deposit=MyDepositIntegration(),
            withdrawal=MyWithdrawalIntegration(),
            toml_func=get_toml_data
        )

These integration classes provide a structured interface for implementing user-defined logic used by Polaris, specifically for deposit and withdrawal flows.

See the integration classes for more information on implementation.

Parameters:
  • deposit – the DepositIntegration subclass instance to be used by Polaris
  • withdrawal – the WithdrawalIntegration subclass instance to be used by Polaris
  • toml_func – a function that returns stellar.toml data as a dictionary
Raises:
  • ValueError – missing argument(s)
  • TypeError – arguments are not subclasses of DepositIntegration or Withdrawal