Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
478 lines (357 sloc) 24.2 KB

Preamble

SEP: 0006
Title: Anchor/Client interoperability
Author: stellar.org
Status: Accepted
Created: 2017-10-30
Updated: 2018-11-07
Version 2.2.1

Simple Summary

This SEP defines the standard way for anchors and wallets to interact on behalf of users. This improves user experience by allowing wallets and other clients to interact with anchors directly without the user needing to leave the wallet to go to the anchor's site.

Abstract

This proposal defines a standard protocol enabling the following features directly within a wallet or other Stellar client:

  • Deposit external assets with an anchor
  • Withdraw assets from an anchor
  • Communicate deposit & withdrawal fee structure for an anchor to the user
  • Handle anchor KYC needs, including transmitting KYC information about the user to the anchor via SEP-12
  • Check the status of ongoing deposits or withdrawals involving the user
  • View history of deposits and withdrawals involving the user

To support this protocol an anchor acts as a server and implements the specified REST API endpoints, while a wallet implements a client that consumes the API. The goal is interoperability, so a wallet implements a single client according to the protocol, and will be able to interact with any compliant anchor. Similarly, an anchor that implements the API endpoints according to the protocol will work with any compliant wallet.

Prerequisites

  • An anchor must define the location of their TRANSFER_SERVER in their stellar.toml. This is how a wallet knows where to find the anchor's server.
  • Anchors may support SEP-12 customer info transfer if they need to handle KYC-ing customers
  • Anchors and clients may support SEP-10 web authentication to enable authenticated deposits, withdrawals, or transaction history lookups

API Endpoints

Deposit

A deposit is when a user sends an external token (BTC via Bitcoin, USD via bank transfer, etc...) to an address held by an anchor. In turn, the anchor sends an equal amount of tokens on the Stellar network (minus fees) to the user's Stellar account.

The deposit endpoint allows a wallet to get deposit information from an anchor, so a user has all the information needed to initiate a deposit. It also lets the anchor specify additional information (if desired) that the user must submit via SEP-12 to be able to deposit.

Request

GET TRANSFER_SERVER/deposit

Request Parameters:

Name Type Description
asset_code string The code of the asset the user wants to deposit with the anchor. Ex BTC,ETH,USD,INR,etc. This may be different from the asset code that the anchor issues. Ex if a user deposits BTC and receives MyBTC tokens, asset_code must be BTC.
account G... string The stellar account ID of the user that wants to deposit. This is where the asset token will be sent.
memo_type string (optional) type of memo that anchor should attach to the Stellar payment transaction, one of text, id or hash
memo string (optional) value of memo to attach to transaction, for hash this should be base64-encoded.
email_address string (optional) Email address of depositor. If desired, an anchor can use this to send email updates to the user about the deposit.
type string (optional) Type of deposit. If the anchor supports multiple deposit methods (e.g. SEPA or SWIFT), the wallet should specify type.

Example:

GET https://api.example.com/deposit?asset_code=ETH&account=GACW7NONV43MZIFHCOKCQJAKSJSISSICFVUJ2C6EZIW5773OU3HD64VI

Response

There are five possible kinds of response, depending on whether the anchor needs more information about the user, how it should be sent to the anchor, and if there are any errors.

The first response, the success response, is explained below. The other four possible responses are shared with the withdrawal endpoint, and are explained in the Deposit and Withdraw shared responses section below.

1. Success: no additional information needed

Response code: 200 OK

This is the correct response if the anchor is able to accept the deposit and needs no additional information about the user. It should also be used if the anchor requires information about the user, but the information has previously been submitted and accepted.

The response body should be a JSON object with the following fields:

Name Type Description
how string Instructions for how to deposit the asset. In the case of cryptocurrency it is just an address to which the deposit should be sent.
eta int (optional) Estimate of how long the deposit will take to credit in seconds.
min_amount float (optional) Minimum amount of an asset that a user can deposit.
max_amount float (optional) Maximum amount of asset that a user can deposit.
fee_fixed float (optional) Fixed fee (if any). In units of the deposited asset.
fee_percent float (optional) Percentage fee (if any). In units of percentage points.
extra_info object (optional) Any additional data needed as an input for this deposit, example: Bank Name

Example:

{
  "how" : "1Nh7uHdvY6fNwtQtM1G5EZAFPLC33B59rB",
  "fee_fixed" : 0.0002
}

If the given Stellar account does not exist, on receipt of the deposit, the anchor should use create_account to create the account with at least enough XLM for the minimum reserve and a trust line (2.01 XLM is recommended). The anchor should take some of the asset that is sent in to pay for the XLM. The anchor should not list this minimal funding as a fee because the user still receives the value of the XLM in their account. The anchor should detect if the account has been created before returning deposit information, and adjust the min_amount in the response to be at least the amount needed to create the account.

Since the anchor doesn't have the user account's secret key, the user must create a trust line to the anchor's asset before the anchor can send the remaining asset tokens to the user's account. The anchor should listen for the user to establish this trust line. Once the trust line is there, the anchor should send the remaining asset tokens to the account in Stellar to complete the deposit.

If the anchor does not support creating new accounts for users and account doesn't exist yet, the anchor should return a 400 Bad Request error. The response body should be a JSON object containing an error field that explains why the request failed.

In the case where the account has already been created, the wallet or client should ensure that the user has already trusted the asset before initiating the deposit flow.

Withdraw

This operation allows a user to redeem an asset currently on the Stellar network for the real asset (BTC, USD, stock, etc...) via the anchor of the Stellar asset.

The withdraw endpoint allows a wallet to get withdrawal information from an anchor, so a user has all the information needed to initiate a withdrawal. It also lets the anchor specify additional information (if desired) that the user must submit via SEP-12 to be able to withdraw.

Request

GET TRANSFER_SERVER/withdraw

Request parameters:

Name Type Description
type string Type of withdrawal. Can be: crypto, bank_account, cash, mobile, bill_payment or other custom values
asset_code string Code of the asset the user wants to withdraw. This must match the asset code issued by the anchor. Ex if a user withdraws MyBTC tokens and receives BTC, the asset_code must be MyBTC.
dest string The account that the user wants to withdraw their funds to. This can be a crypto account, a bank account number, IBAN, mobile number, or email address.
dest_extra string (optional) Extra information to specify withdrawal location. For crypto it may be a memo in addition to the dest address. It can also be a routing number for a bank, a BIC, or the name of a partner handling the withdrawal.
account G... string (optional) The stellar account ID of the user that wants to do the withdrawal. This is only needed if the anchor requires KYC information for withdrawal. The anchor can use account to look up the user's KYC information.
memo string (optional) A wallet will send this to uniquely identify a user if the wallet has multiple users sharing one Stellar account. The anchor can use this along with account to look up the user's KYC info.
memo_type string (optional) type of memo. One of text, id or hash

Example:

GET https://api.example.com/withdraw?asset_code=ETH&dest=0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe

Response

There are five possible kinds of response, depending on whether the anchor needs more information about the user, how it should be sent to the anchor, and if there are any errors.

The first response, the success response, is explained below. The other four possible responses are shared with the deposit endpoint, and are explained in the Deposit and Withdraw shared responses section directly below.

1. Success: no additional information needed

Response code: 200 OK

This is the correct response if the anchor is able to execute the withdrawal and needs no additional information about the user. It should also be used if the anchor requires information about the user, but the information has previously been submitted and accepted.

The response body should be a JSON object with the following fields:

Name Type Description
account_id G... string The account the user should send its token back to.
memo_type string (optional) type of memo to attach to transaction, one of text, id or hash
memo string (optional) value of memo to attach to transaction, for hash this should be base64-encoded.
eta int (optional) Estimate of how long the withdrawal will take to credit in seconds.
min_amount float (optional) Minimum amount of an asset that a user can withdraw.
max_amount float (optional) Maximum amount of asset that a user can withdraw.
fee_fixed float (optional) If there is a fee for withdraw. In units of the withdrawn asset.
fee_percent float (optional) If there is a percent fee for withdraw.
extra_info object (optional) Any additional data needed as an input for this withdraw, example: Bank Name

Example:

{
  "account_id": "GCIBUCGPOHWMMMFPFTDWBSVHQRT4DIBJ7AD6BZJYDITBK2LCVBYW7HUQ",
  "memo_type": "id",
  "memo": "123"
}

Deposit and Withdraw shared responses

2. Customer information needed (non-interactive)

Response code: 403 Forbidden

If the anchor needs more information about the customer and all the information can be received non-interactively via SEP-12, this is the correct response. Once the user / wallet transmits information via SEP-12, they can retry the deposit or withdraw endpoint to see if the anchor is ready to execute the deposit or withdrawal.

The response body should be a JSON object with the following fields:

Name Type Description
type string Always set to non_interactive_customer_info_needed
fields list of strings A list of field names that need to be transmitted via SEP-12 for the deposit to proceed.

The field names specified in fields must be drawn from the list defined in SEP-9.

Example:

{
  "type": "non_interactive_customer_info_needed",
  "fields" : ["family_name", "given_name", "address", "tax_id"],
}

3. Customer information needed (interactive)

Response code: 403 Forbidden

An anchor that requires the user to fill out information on a webpage hosted by the anchor should use this response. A wallet that receives this response should open a popup browser window to the specified URL.

The response body should be a JSON object with the following fields:

Name Type Description
type string Always set to interactive_customer_info_needed
url string URL hosted by the anchor. The wallet should show this URL to the user either as a popup or an iframe.
interactive_deposit boolean (optional) Flag indicating that depositing is also handled in the anchor's interactive customer info flow. The wallet need not make additional requests to /deposit to complete the deposit. Defaults to false. Only relevant for responses to /deposit requests.

If the wallet wants to be notified that the user has completed the required actions via the URL, it can add an extra callback parameter to the value of url before opening the browser window. If the callback value is a URL, the anchor should POST to it with a JSON message as the body once the user has successfully completed the process. If callback=postMessage is passed, the anchor should post a JSON message to window.opener via the Javascript Window.postMessage method. If window.opener is undefined, the message should be posted to window.parent instead.

In either case, the JSON message should the same as the Customer Information Status response format, with one change. Since it's possible that the anchor is POSTing or postMessaging a success result, the status field make also be set to success.

Alternatively, the wallet can always poll the original deposit or withdrawal endpoint until a success, status denied, or error response is returned.

Example:

{
  "type": "interactive_customer_info_needed",
  "url" : "https://api.example.com/kycflow?account=GACW7NONV43MZIFHCOKCQJAKSJSISSICFVUJ2C6EZIW5773OU3HD64VI",
  "interactive_deposit": true
}

4. Customer Information Status

Response code: 403 Forbidden

An anchor should use this response if customer information was submitted for the account, but the information is either still being processed or was not accepted.

Name Type Description
type string Always set to customer_info_status
status string Status of customer information processing. One of: pending, denied
more_info_url string (optional) A URL the user can visit if they want more information about their account / status.
eta int (optional) Estimated number of seconds until the deposit status will update.

If the anchor decides that more customer information is needed after receiving some information and processing it, it can respond again with a response of type interactive_customer_info_needed or non_interactive_customer_info_needed. In the case of a denied request, an anchor can use the more_info_url to explain to the user the issue with their request and give them a way to rectify it manually. A wallet should show the more_info_url to the user when explaining that the request was denied.

Note: this status response should never be used in the case that the user's KYC request succeeds. In that case, the anchor should respond with a deposit / withdrawal address as described by those endpoints.

Example:

{
  "type": "customer_info_status",
  "status": "denied",
  "more_info_url": "https://api.example.com/kycstatus?account=GACW7NONV43MZIFHCOKCQJAKSJSISSICFVUJ2C6EZIW5773OU3HD64VI"
}

5. Error

Every other HTTP status code will be considered an error. The body should contain error details. For example:

{
   "error": "This anchor doesn't support the given currency code: ETH"
}

Info

Allows an anchor to communicate basic info about what their TRANSFER_SERVER supports to wallets and clients.

Request

GET TRANSFER_SERVER/info

Request parameters:

Name Type Description
lang string (optional) Defaults to en. Language code specified using ISO 639-1. description fields in the response should be in this language.

Response

The response should be a JSON object like:

{
  "deposit": {
    "USD": {
      "enabled": true,
      "fee_fixed": 5,
      "fee_percent": 1,
      "fields": {
        "email_address" : {
          "description": "your email address for transaction status updates",
          "optional": true
        },
        "amount" : {
          "description": "amount in USD that you plan to deposit"
        },
        "type" : {
          "description": "type of deposit to make",
          "choices": ["SEPA", "SWIFT", "cash"]
        }
      }
    },
    "ETH": {
      "enabled": true,
      "fee_fixed": 0.002,
      "fee_percent": 0
    }
  },
  "withdraw": {
    "USD": {
      "enabled": true,
      "fee_fixed": 5,
      "fee_percent": 0,
      "types": {
        "bank_account": {
          "fields": {
              "dest": {"description": "your bank account number" },
              "dest_extra": { "description": "your routing number" },
              "bank_branch": { "description": "address of your bank branch" },
              "phone_number": { "description": "your phone number in case there's an issue" }
          }
        },
        "cash": {
          "fields": {
            "dest": { "description": "your email address. Your cashout PIN will be sent here." }
          }
        }
      }
    },
    "ETH": {
      "enabled": false
    }
  },
  "transactions": {
    "enabled": true
  }
}

The JSON object contains an entry for each asset that the anchor supports for SEP6 deposit and/or withdrawal.

For each deposit asset, it contains:

  • enabled: set if SEP-6 deposit for this asset is supported
  • The fee structure
  • fields object as explained below.

For each withdrawal asset, it contains:

  • enabled: set if SEP-6 withdrawal for this asset is supported
  • The fee structure
  • a types field with each type of withdrawal supported for that asset as a key. Each type can specify a fields object as below explaining what fields are needed and what they do.

The fields object allows an anchor to describe fields that are passed into /deposit and /withdraw. It can explain standard fields like dest and dest_extra for withdrawal, and it can also specify extra fields that should be passed into /deposit or /withdraw such as an email address or bank name. If a field is part of the KYC/AML flow handled by SEP-12 or the field is handled by your interactive deposit/withdrawal flow, there's no need to list it in /info. Only fields that are passed to /deposit or /withdraw need appear here.

The fields object contains a key for each field name and an object with the following fields as the value:

  • description: description of field to show to user
  • optional: if field is optional. Defaults to false.
  • choices: list of possible values for the field.

The wallet should display a form to the user to fill out any fields with unknown values as part of the deposit/withdrawal flow. Each field should be an text input, unless choices is specified, in which case a dropdown should be used.

An anchor should also specify if they support the /transactions endpoint under the "transactions" key.

Transaction History

The transaction history endpoint helps anchors enable a better experience for users using an external wallet. With it, wallets can display the status of deposits and withdrawals while they process and a history of past transactions with the anchor. It's only for transactions that are deposits to or withdrawals from the anchor.

GET TRANSFER_SERVER/transactions

Request parameters:

Name Type Description
asset_code string The code of the asset of interest. E.g. BTC,ETH,USD,INR,etc
account string The stellar account ID involved in the transactions
no_older_than UTC ISO 8601 string (optional) The response should contain transactions starting on or after this date & time
limit int (optional) the response should contain at most limit transactions
paging_id string (optional) the response should contain transactions starting prior to this ID (exclusive)

On success the endpoint should return 200 OK HTTP status code and a JSON object with the following fields:

Name Type Description
transactions array List of transactions as requested by the client, sorted in time-descending order

Each object in the transactions array should have the following fields:

Name Type Description
id string Unique, anchor-generated id for the deposit/withdrawal
kind string deposit or withdrawal
status string Processing status of deposit/withdrawal
status_eta number (optional) Estimated number of seconds until a status change is expected
amount_in string (optional) Amount received by anchor at start of transaction as a string with up to 7 decimals. Excludes any fees charged before the anchor received the funds.
amount_out string (optional) Amount sent by anchor to user at end of transaction as a string with up to 7 decimals. Excludes amount converted to XLM to fund account and any external fees
amount_fee string (optional) Amount of fee charged by anchor
from string (optional) Sent from address (perhaps BTC or bank in the case of a deposit, stellar address in the case of a withdrawal)
to string (optional) Sent to address (perhaps BTC or bank in the case of a withdrawal, stellar address in the case of a deposit)
started_at UTC ISO 8601 string (optional) start date and time of transaction
completed_at UTC ISO 8601 string (optional) completion date and time of transaction
stellar_transaction_id string (optional) transaction_id on Stellar network of the transfer that either completed the deposit or started the withdrawal
external_transaction_id string (optional) ID of transaction on external network that either started the deposit or completed the withdrawal
message string (optional) Human readable explanation of transaction status, if needed.

status should be one of:

  • completed -- deposit/withdrawal fully completed
  • pending_external -- deposit/withdrawal has been submitted to external network, but is not yet confirmed. This is the status when waiting on Bitcoin or other external crypto network to complete a transaction, or when waiting on a bank transfer.
  • pending_anchor -- deposit/withdrawal is being processed internally by anchor
  • pending_stellar -- deposit/withdrawal operation has been submitted to Stellar network, but is not yet confirmed
  • pending_trust -- the user must add a trust-line for the asset for the deposit to complete
  • pending_user -- the user must take additional action before the deposit / withdrawal can complete
  • no_market -- could not complete deposit because no satisfactory asset/XLM market was available to create the account
  • too_small -- deposit/withdrawal size less than min_amount
  • too_large -- deposit/withdrawal size exceeded max_amount
  • error -- catch-all for any error not enumerated above

Example response:

{
  "transactions": [
    {
      "id": "82fhs729f63dh0v4",
      "kind": "deposit",
      "status": "pending_external",
      "status_eta": 3600,
      "external_transaction_id": "2dd16cb409513026fbe7defc0c6f826c2d2c65c3da993f747d09bf7dafd31093",
      "amount_in": "18.34",
      "amount_out": "18.24",
      "amount_fee": "0.1",
      "started_at": "2017-03-20T17:05:32Z"
    },
    {
      "id": "82fhs729f63dh0v4",
      "kind": "withdrawal",
      "status": "completed",
      "amount_in": "500",
      "amount_out": "495",
      "amount_fee": "3",
      "started_at": "2017-03-20T17:00:02Z",
      "completed_at": "2017-03-20T17:09:58Z",
      "stellar_transaction_id": "17a670bc424ff5ce3b386dbfaae9990b66a2a37b4fbe51547e8794962a3f9e6a",
      "external_transaction_id": "2dd16cb409513026fbe7defc0c6f826c2d2c65c3da993f747d09bf7dafd31093"
    }
  ]
}

Every HTTP status code other than 200 OK will be considered an error. An empty transaction list is not an error. The body should contain error details. For example:

{
   "error": "This anchor doesn't support the given currency code: ETH"
}

Implementations