Skip to content

Latest commit

 

History

History
625 lines (480 loc) · 41 KB

sep-0038.md

File metadata and controls

625 lines (480 loc) · 41 KB

Preamble

SEP: 0038
Title: Anchor RFQ API
Author: Jake Urban <@jakeurban> and Leigh McCulloch <@leighmcculloch>
Track: Standard
Status: Draft
Created: 2021-04-09
Updated: 2023-08-24
Discussion: https://github.com/stellar/stellar-protocol/issues/901
Version 2.2.0

Summary

This protocol enables anchors to accept off-chain assets in exchange for different on-chain assets, and vice versa. Specifically, it enables anchors to provide quotes that can be referenced within the context of existing Stellar Ecosystem Proposals. How the exchange of assets is facilitated is outside the scope of this document.

Motivation

Anchoring an asset and issuing an asset are distinct functions that have different business and technical requirements. However, issuing an asset has often been a prerequisite for anchoring an asset. This protocol enables anchors to transfer value on and off the Stellar network for their clients regardless of whether a one-for-one reserve-backed Stellar asset exists for the off-chain asset held by the anchor's clients.

Removing this requirement for anchors also provides downstream benefits to ecosystem participants generally. Enabling anchors to accept any Stellar asset will naturally decrease liquidity fragmentation on the decentralized exchange, leading to greater market depth and tighter spreads between trading pairs.

Specification

stellar.toml

An anchor must define the location of their ANCHOR_QUOTE_SERVER in their stellar.toml. This is how a wallet knows where to find the anchor's server.

Authentication

This protocol's endpoints use authentication in the form of a SEP-10 JSON Web Token (JWT) in the Authorization header of the request.

Authentication is mandatory for POST /quote and GET /quote/:id, but optional for the remaining endpoints. When optional, if authentication is provided it can be used to personalize the respective responses.

Authorization: Bearer <jwt>

Content Type

All endpoints accept in requests the following Content-Type:

  • application/json

All endpoints respond with content type:

  • application/json

Errors

If an error occurs when calling any endpoint, an appropriate HTTP status code will be returned along with an error response.

Status Code

Common HTTP status codes may be returned for a server. In particular the following are expected:

Status Code Name Reason
400 Bad Request The request is invalid in any way.
403 Permission Denied No Authorization header has been provided or the contents of the header are not accepted as valid.

The response body must contain a human-readable description of the reason for error:

{
  "error": "The requested asset is not supported. See GET /prices for supported assets."
}

Asset Identification Format

This protocol can be used to provide quotes for any class of asset in exchange for a Stellar asset. The following format is used to identify an asset in API requests and responses.

<scheme>:<identifer>

The currently accepted scheme values are:

Name Description
stellar Used for Stellar assets.
iso4217 Used for fiat currencies.

stellar Identifier Format

The SEP-11 asset format.

iso4217 Identifier Format

The ISO 4217 three-character currency code for the fiat currency.

For example, Stellar USDC would be identified as:

stellar:USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN

Fiat USD would be identified as:

iso4217:USD

Endpoints

GET Info

This endpoint describes the supported Stellar assets and off-chain assets available for trading. Note that the anchor may not support a trading pair between every Stellar asset and off-chain asset listed. Use the GET /prices endpoint to see which pairs are supported.

Authentication

Optional SEP-10. If authentication is provided it can be used to personalize the response.

Request

No request arguments required.

Response

A 200 Success status code should be returned for successful requests.

Name Type Description
assets array An array of objects describing the assets available in exchange for one or more of the other assets listed.

assets Object Schema

Name Type Description
asset string The Asset Identification Format value.
sell_delivery_methods array (optional) Only for non-Stellar assets. An array of objects describing the methods a client can use to sell/deliver funds to the anchor. The method of delivery may affect the expiration and/or price provided in a POST /quote response. If the delivery method is not necessary for providing accurate quotes and expirations, the server can omit this attribute.
buy_delivery_methods array (optional) Only for non-Stellar assets. An array of objects describing the methods a client can use to buy/retrieve funds from the anchor. The method of delivery may affect the expiration and/or price provided in a POST /quote response. If the delivery method is not necessary for providing accurate quotes and expirations, the server can omit this attribute.
country_codes array (optional) Only for fiat assets. A list of ISO 3166-2 codes of the countries where the Anchor operates for fiat transactions. Anchor may not require second part of the ISO 3166-2 to be passed (i.e. use ISO-3166-1 alpha-2 instead).

Object Schema for sell_delivery_methods and buy_delivery_methods.

Name Type Description
name string The value to use when making POST /quote requests.
description string A human readable description of the method identified by name.
Example

GET /info

{
  "assets": [
    {
      "asset": "stellar:USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"
    },
    {
      "asset": "stellar:BRL:GDVKY2GU2DRXWTBEYJJWSFXIGBZV6AZNBVVSUHEPZI54LIS6BA7DVVSP"
    },
    {
      "asset": "iso4217:BRL",
      "country_codes": ["BRA"],
      "sell_delivery_methods": [
        {
          "name": "cash",
          "description": "Deposit cash BRL at one of our agent locations."
        },
        {
          "name": "ACH",
          "description": "Send BRL directly to the Anchor's bank account."
        },
        {
          "name": "PIX",
          "description": "Send BRL directly to the Anchor's bank account."
        }
      ],
      "buy_delivery_methods": [
        {
          "name": "cash",
          "description": "Pick up cash BRL at one of our payout locations."
        },
        {
          "name": "ACH",
          "description": "Have BRL sent directly to your bank account."
        },
        {
          "name": "PIX",
          "description": "Have BRL sent directly to the account of your choice."
        }
      ]
    }
  ]
}

GET Prices

This endpoint can be used to fetch the indicative prices of available off-chain assets in exchange for a Stellar asset and vice versa.

These prices are indicative. The actual price will be calculated at conversion time once the Anchor receives the funds from a User.

The prices returned include any margin that the provider may keep as a service fee, and this margin may vary depending on the directional flow of funds, amount, delivery method, country code, or other factors.

Authentication

Optional SEP-10. If authentication is provided it can be used to personalize the response.

Request

Name Type Description
sell_asset string The asset you want to sell, using the Asset Identification Format.
sell_amount string The amount of sell_asset the client would exchange for each of the buy_assets.
sell_delivery_method string (optional) One of the name values specified by the sell_delivery_methods array for the associated asset returned from GET /info. Can be provided if the user is delivering an off-chain asset to the anchor but is not strictly required.
buy_delivery_method string (optional) One of the name values specified by the buy_delivery_methods array for the associated asset returned from GET /info. Can be provided if the user intends to receive an off-chain asset from the anchor but is not strictly required.
country_code string (optional) The ISO 3166-2 or ISO-3166-1 alpha-2 code of the user's current address. Should be provided if there are two or more country codes available for the desired asset in GET /info.

Response

A 200 Success status code should be returned for successful requests.

Name Type Description
buy_assets array An array of objects containing information on the assets that the client will receive when they provide sell_asset.

buy_assets Object Schema

Name Type Description
asset string The Asset Identification Format value.
price string The price offered by the anchor for one unit of asset in terms of sell_asset. In traditional finance, asset would be referred to as the base asset and sell_asset as the counter asset.
decimals integer The number of decimals needed to represent asset.
Examples
GET /prices?sell_asset=stellar:USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN&sell_amount=100&country_code=BRA&buy_delivery_method=ACH
{
  "buy_assets": [
    {
      "asset": "iso4217:BRL",
      "price": "0.18",
      "decimals": 2
    }
  ]
}

GET /prices?sell_asset=iso4217:BRL&sell_amount=500&country_code=BRA&sell_delivery_method=PIX
{
  "buy_assets": [
    {
      "asset": "stellar:USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN",
      "price": "5.42",
      "decimals": 7
    }
  ]
}

GET Price

This endpoint can be used to fetch the indicative price for a given asset pair.

The client must provide either sell_amount or buy_amount, but not both.

These prices are indicative. The actual price will be calculated at conversion time once the Anchor receives the funds from a User.

Fees can be collected by adding a margin to the price, and/or by deducting an amount from the funds provided by or delivered to the client. Both the margin and the fees may vary depending on the directional flow of funds, amount, delivery method, country code, context or other factors.

Authentication

Optional SEP-10. If authentication is provided it can be used to personalize the response.

Request

Name Type Description
sell_asset string The asset the client would like to sell. Ex. USDC:G..., iso4217:ARS
buy_asset string The asset the client would like to exchange for sell_asset.
sell_amount string The amount of sell_asset the client would like to exchange for buy_asset.
buy_amount string The amount of buy_asset the client would like to purchase with sell_asset.
sell_delivery_method string (optional) One of the name values specified by the sell_delivery_methods array for the associated asset returned from GET /info. Can be provided if the user is delivering an off-chain asset to the anchor but is not strictly required.
buy_delivery_method string (optional) One of the name values specified by the buy_delivery_methods array for the associated asset returned from GET /info. Can be provided if the user intends to receive an off-chain asset from the anchor but is not strictly required.
country_code string (optional) The ISO 3166-2 or ISO-3166-1 alpha-2 code of the user's current address. Should be provided if there are two or more country codes available for the desired asset in GET /info.
context string The context for what this quote will be used for. Must be one of sep6 or sep31.

Response

A 200 Success status code should be returned for successful requests.

Name Type Description
total_price string The total conversion price offered by the anchor for one unit of buy_asset in terms of sell_asset, including fees. In traditional finance, buy_asset would be referred to as the base asset and sell_asset as the counter asset.
price string The conversion price offered by the anchor for one unit of buy_asset in terms of sell_asset, without including fees. In traditional finance, buy_asset would be referred to as the base asset and sell_asset as the counter asset.
sell_amount string The amount of sell_asset the anchor will exchange for buy_asset. It could be different from the sell_amount provided in the request, depending on how fees are applied by the Anchor.
buy_amount string The amount of buy_asset the anchor will provide with sell_asset. It could be different from the buy_amount provided in the request, depending on how fees are applied by the Anchor.
fee object An object describing the fee used to calculate the conversion price. This can be used to datail the price components for the end-user.

To better understand the relation between the *price, *amount and fee fields, please refer to the Price Formulas section.

Object Schema for fee:

Name Type Description
total string The total amount of fee applied.
asset string The asset in which the fee is applied, represented through the Asset Identification Format.
details array (optional) An array of objects detailing the fees that were used to calculate the conversion price. This can be used to datail the price components for the end-user.

Object Schema for fee.details:

Name Type Description
name string The name of the fee, for example ACH fee, Brazilian conciliation fee, Service fee, etc.
description string (optional) A text describing the fee.
amount string The amount of asset applied. If fee.details is provided, sum(fee.details.amount) should be equals fee.total.
Examples
GET /price?sell_asset=iso4217:BRL&buy_asset=stellar:USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN&sell_amount=500&sell_delivery_method=PIX&country_code=BRA&context=sep6
{
  "total_price": "5.42",  // 542/100
  "price": "5.00",        // (542-42)/100
  "sell_amount": "542",
  "buy_amount": "100",
  "fee": {
    "total": "42.00",
    "asset": "iso4217:BRL"
  }
}

GET /price?sell_asset=iso4217:BRL&buy_asset=stellar:USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN&buy_amount=100&sell_delivery_method=PIX&country_code=BRA&context=sep31
{
  "total_price": "5.42",      // 542/100
  "price": "5.00",            // 542/(100+8.40)
  "sell_amount": "542",
  "buy_amount": "100",
  "fee": {
    "total": "8.40",
    "asset": "stellar:USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN",
    "details": [
      {
        "name": "Service fee",
        "amount": "8.40"
      }
    ]
  }
}

GET /price?sell_asset=stellar:USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN&buy_asset=iso4217:BRL&sell_amount=90&buy_delivery_method=PIX&country_code=BRA&context=sep6
{
  "total_price": "0.20",      // 100/500
  "price": "0.18",            // 100/(500+55.5556)
  "sell_amount": "100",
  "buy_amount": "500",
  "fee": {
    "total": "55.5556",
    "asset": "iso4217:BRL",
    "details": [
      {
        "name": "PIX fee",
        "description": "Fee charged in order to process the outgoing PIX transaction.",
        "amount": "55.5556"
      }
    ]
  }
}

GET /price?sell_asset=stellar:USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN&buy_asset=iso4217:BRL&buy_amount=500&buy_delivery_method=PIX&country_code=BRA&context=sep31
{
  "total_price": "0.20",  // 100/500
  "price": "0.18",        // (100-10)/500
  "sell_amount": "100",
  "buy_amount": "500",
  "fee": {
    "total": "10.00",
    "asset": "stellar:USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN",
    "details": [
      {
        "name": "Service fee",
        "amount": "5.00"
      },
      {
        "name": "PIX fee",
        "description": "Fee charged in order to process the outgoing BRL PIX transaction.",
        "amount": "5.00"
      }
    ]
  }
}

Price Formulas

The following should hold true for all prices and quotes returned in the SEP-38 responses.

sell_amount = total_price * buy_amount;
sell_amount - fee = price * buy_amount    // when `fee` is in `sell_asset`

- or -

sell_amount = price * (buy_amount + fee)  // when `fee` is in `buy_asset`

POST Quote

This endpoint can be used to request a firm quote for a Stellar asset and off-chain asset pair.

In contrast with the GET /price and GET /prices endpoints, the amount requested must be held in reserve and not used in calculations of subsequent quotes until the expiration provided in the response.

Protecting Against Bad Actors

To protect against bad actor clients reserving all available capital without following through with the requested trades, servers should only accept requests for quotes from Stellar accounts that belong to entities or individuals that have been properly KYC'ed, either via SEP-12 or some other mechanism.

Servers may deny access to the API if misuse is detected.

Transaction Fees

Fees can be collected by adding a margin to the price, and/or by deducting an amount from the funds provided by or delivered to the client. Both the margin and the fees may vary depending on the directional flow of funds, amount, delivery method, country code, context or other factors.

If the client requests some amount of an off-chain asset for providing some amount of a Stellar asset, the client will submit a Stellar transaction delievering funds to the anchor before the expiration included in the response, paying a fee as determined by state of the Stellar network.

In the reverse scenario, the anchor will submit a Stellar transaction to deliver funds to the client as long as the client delivered off-chain funds to the anchor before the expiration. In this case, the anchor will likely increase their margin to cover the cost of submitting the transaction.

Authentication

SEP-10.

Request

The client must provide either sell_amount or buy_amount, but not both.

Unless the list included in the GET /info response is empty or missing for the associated off-chain asset, the client must also provide either sell_delivery_method or buy_delivery_method, but not both.

Name Type Description
sell_asset string Same as the definition of sell_asset in GET /price.
buy_asset string Same as the definition of buy_asset in GET /price.
sell_amount string Same as the definition of sell_amount in GET /price.
buy_amount string The same definition of buy_amount in GET /price.
expire_after UTC ISO 8601 string (optional) The client's desired expires_at date and time for the quote. Anchors may choose an expires_at that occurs after the expire_after. Anchors should return 400 Bad Request if the an expiration on or after the requested value cannot be provided.
sell_delivery_method string (optional) One of the name values specified by the sell_delivery_methods array for the associated asset returned from GET /info. Must be provided if the user is delivering an off-chain asset to the anchor unless no more than one method is specified in the GET /info response.
buy_delivery_method string (optional) One of the name values specified by the buy_delivery_methods array for the associated asset returned from GET /info. Must be provided if the user intends to receive an off-chain asset from the anchor unless no more than one method is specified in the GET /info response.
country_code string (optional) The ISO 3166-2 or ISO-3166-1 alpha-2 code of the user's current address. Should be provided if there are two or more country codes available for the desired asset in GET /info.
context string The context for what this quote will be used for. Must be one of sep6, sep24 or sep31.

Response

A 201 Created status code should be returned for successful requests.

Name Type Description
id string The unique identifier for the quote to be used in other Stellar Ecosystem Proposals (SEPs).
expires_at UTC ISO 8601 string The date and time by which the anchor must receive funds from the client.
total_price string The total conversion price offered by the anchor for one unit of buy_asset in terms of sell_asset, including fees. In traditional finance, buy_asset would be referred to as the base asset and sell_asset as the counter asset.
price string The conversion price offered by the anchor for one unit of buy_asset in terms of sell_asset, without including fees. In traditional finance, buy_asset would be referred to as the base asset and sell_asset as the counter asset.
sell_asset string The asset the client would like to sell. Ex. USDC:G..., iso4217:ARS
sell_amount string The amount of sell_asset to be exchanged for buy_asset. It could be different from the sell_amount provided in the request, depending on how fees are applied by the Anchor.
buy_asset string The asset the client would like to exchange for sell_asset.
buy_amount string The amount of buy_asset to be exchanged for sell_asset. It could be different from the buy_amount provided in the request, depending on how fees are applied by the Anchor. price * buy_amount = sell_amount must be true up to the number of decimals required for buy_asset.
fee object An object describing the fee used to calculate the conversion price. This can be used to datail the price components for the end-user.

To better understand the relation between the *price, *amount and fee fields, please refer to the Price Formulas section.

GET Quote

This endpoint can be used to fetch a previously-provided firm quote. Quotes referenced in other protocols must be available at this endpoint past the expires_at expiration for the quote.

Authentication

SEP-10.

Request

Name Type Description
id string The unique identifier for the quote. Same as the id returned in the POST /quote response.

Response

This response body should match the response from POST /quote.

Name Type Description
id string The id specified in the request.
expires_at UTC ISO 8601 string The date and time by which the anchor must receive funds from the client.
price string The price offered by the anchor for one unit of buy_asset in terms of sell_asset. In traditional finance, buy_asset would be referred to as the base asset and sell_asset as the counter asset.
sell_asset string The asset the client would like to sell. Ex. USDC:G..., iso4217:ARS
sell_amount string The amount of sell_asset to be exchanged for buy_asset.
buy_asset string The asset the client would like to exchange for sell_asset.
buy_amount string The amount of buy_asset to be exchanged for sell_asset. price * buy_amount = sell_amount must be true up to the number of decimals required for buy_asset.
fee object An object describing the fee used to calculate the conversion price. This can be used to datail the price components for the end-user.
Example
GET /quote/de762cda-a193-4961-861e-57b31fed6eb3
{
  "id": "de762cda-a193-4961-861e-57b31fed6eb3",
  "expires_at": "2021-04-30T07:42:23",
  "total_price": "5.42",        // 542/100
  "price": "5.00",              // (542-42)/100
  "sell_asset": "iso4217:BRL",
  "sell_amount": "542",
  "buy_asset": "stellar:USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN&",
  "buy_amount": "100",
  "fee": {
    "total": "42.00",
    "asset": "iso4217:BRL",
    "details": [
      {
        "name": "PIX fee",
        "description": "Fee charged in order to process the outgoing PIX transaction.",
        "amount": "12.00"
      },
      {
        "name": "Brazilian conciliation fee",
        "description": "Fee charged in order to process conciliation costs with intermediary banks.",
        "amount": "15.00"
      },
      {
        "name": "Service fee",
        "amount": "15.00"
      }
    ]
  }
}

Changelog

  • v2.2.0: Switch from ISO-3166-1 alpha-3 country code to ISO-3166-2/ISO-3166-1 alpha-3 country code in the requests (where applicable). (#1386)
  • v2.1.0: Add sep24 support to the context of the request body of the POST /quote request. (#1358)
  • v2.0.0: (i) add context to the request body and fee + total_price to the response body of the POST /quote and GET /price requests; (ii) add fee to the response body of GET /quote/:id; and (iii) allow sell_amount and buy_amount in the responses to be different from the ones sent in the request. (#1204)
  • v1.6.1: Add note about expires_at and expires_after and their relationship. (#1147)
  • v1.6.0: Make SEP-10 authentication token optional for the GET /info, GET /price and GET /prices endpoints. (#1144)