How to | Developers

How to

Estimated reading time: 8 minutes

What do we need ?

In order to become a swap provider in the Ledger Live ecosystem, you must:

  1. Submit your API following Ledger’s specifications. We will guide you through the requirements and the modifications you will need to apply to your API before sending it to us.
  2. Provide to Ledger your public key that will be used to encode the swap info.
  3. Submit your LiveApp following Ledger’s specfication.

This diagram shows what is needed from the provider’s side in order to interact with Ledger Live.

How to diagram

Provider’s Endpoints

In order to communicate with Ledger’s back-end, you have to give us the mapping of the endpoints we need.
As you can see on the diagram above, there are 4 main endpoints needed for the swap:

  • To get the list of available currencies: /currencies.
  • To get the list of tradable pairs: /pairs.
  • To query a rate: /quote.
  • To query a swap status: /status.

You will find the details about each needed endpoint below.

GET /currencies

  • Function: Returns a list of supported currencies.
  • Input: –
  • Output: Array of supported currencies, with information required to uniquely identify coins/tokens.
  • Payload:
    [
    {
      "id":"BTC",
      "type":"coin",
      "blockchain":"bitcoin",
      "chainId":1
    },
    {
      "id":"USDC",
      "type":"token",
      "blockchain":"ethereum",
      "chainId":1,
      "contract":"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
    }
    ]
    

GET /pairs

  • Function: Returns a list of supported pairs. This endpoint is not required if all permutations returned by /currencies are supported.
  • Input: –
  • Output: Array of supported swap pairs, with supported quote type (fixed / float).
  • Payload:
    [
     {
        "from":"btc",
        "to":"bat",
        "tradeMethod":[
           "fixed",
           "float"
        ]
     },
     {
        "from":"bat",
        "to":"btc",
        "tradeMethod":[
           "fixed",
           "float"
        ]
     }
    ]
    

Fixed quote: The quote price is guaranteed until execution (or until end of quote validity period).
Float quote: The quote price is indicative only, real price is computed at execution time

POST /quote

  • Function: Returns a quote for a pair and amount.
  • Input: from, to, amount.
  • Output:
    • method: fixed or float (optional, only required for consistency check)
    • quoteId: quote unique identifier (optional, only required for fixed quotes)
    • expiry: quote expiration timestamp (optional, only required for fixed quotes)
    • minAmountFrom: minimum valid amount for this pair (optional, only required if amount is too low)
    • maxAmountFrom: maximum valid amount for this pair (optional, only required if amount is too large)
    • amountFrom: should be same as amount (optional, only required for consistency check) (as an input coin floating amount)
    • amountTo: estimated output amount that will be sent to user (as an output coin floating amount)
    • payoutNetworkFees: estimated gas fees that will be used for the payout transaction (as an output coin floating amount)
  • Payload:
    • Success
      {
       "quoteId":"id1",
       "from":"btc",
       "to":"bat",
       "amountFrom":"1",
       "amountTo":"40000",
       "payoutNetworkFees": "0.0002",
       "rate":"37800.21",
       "tradeMethod":"float",
       "expiry": "date"  
      }
      

Note: the final estimated amount received by the user should be amountTo - payoutNetworkFees.

Some requirements about the /quote endpoint:

  • The quote must work without user auth. It can require a Ledger auth.
  • The quote must be valid long enough (at least a few minutes).

GET /status

  • Function: Returns the status of an executed swap transaction.
  • Input: swapId.
  • Output:
    • status:
      • FINISHED: Trade has been completed successfully (user has received payout transaction).
      • EXPIRED: Payin transaction was not received in time, trade is cancelled. User will be refunded if payin transaction is received afterwards.
      • ON_HOLD: Trade has been put on hold (eg: for KYC reasons). User must contact support.
      • PENDING: Trade is in progress (partner is waiting to receive payin transaction, or user is waiting to receive payout transaction)
      • REFUNDED: Trade has been cancelled, refund transaction has been successfully received by user.
      • UNKNOWN: Trade is in unknown state. User must contact support.
    • amount: as soon as this information is known, this should contain the final amount transferred to the user in output currency
    • payinTransactionId: as soon as this information is known, this should contain the payin transaction hash
    • payoutTransactionId: as soon as this information is known, this should contain the payout transaction hash
  • Payload:
    • Success
      {
       "quoteId":"id1",
       "status":"FINISHED",
       "amount": 1.337,
       "payinTransactionId": "0xfffffffffffff",
       "payoutTransactionId": "0xfffffffffffff"
      }
      

Ledger’s Endpoint

To complete the transaction, you need to provide to the LiveApp SDK a payload that will be signed by the user’s device (e.g. Ledger Nano).

POST /swap/payload

  • Function: Create a binary payload which contains all information needed to fullfil a swap transaction.
  • Input:
    • provider: your id or name known by Ledger for identification purpose.
    • swapId: provider’s id of the ongoing swap transaction. This will be used by Ledger’s backend to retrieve the status of user swap transaction.
    • payinAddress: provider’s address.
    • refundAddress: refund address.
    • payoutAddress: payout transaction address.
    • currencyFrom: from currency id, using your identifiers.
    • currencyTo: to currency id, using you identifiers.
    • amountToProvider: amount of currencyFrom that the provider expects to receive from client.
    • amountToWallet: amount of currencyTo that the provider agrees to send to the client in exchange from amountToProvider. This amount must also include the network fees that the provider will pay to send the crypto to the user.
    • nonce: value to use for device_transaction_id field in the protobuf payload.
  • Output: payload in a binary format.
    In case of an error, returns the same payload as /check_quote.

Provider’s LiveApp

The LiveApp needs to respond to a deeplink with some parameters.

The deeplink format is already fixed and will depend on the information you provided inside your LiveApp manifest (ex: ledgerlive://discover/swapprovidername). The query params for this deeplink are:

  • quoteId: The id retrieved by Ledger’s backend during a quote request
  • fromAddress: The user’s address that will be used for the payin transaction.
  • toAddress: The user’s address that will be used for the payout transaction.

Example: ledgerlive://discover/swapprovidername?quoteId=1234&fromAddress=0xFFFFFFF&toAddress=0xFFFFFFF

Ledger’s WalletAPI SDK

To learn how to create (or embed if already existing) your user interface for the swap, please follow this tutorial.

Your LiveApp will interact with Ledger Live with 2 differents methods:

Those methods are more detailed in github

startExchange

This method will return you a nonce.

A nonce field will is the last parameter you need to provide to the /swap endpoint.
It is a 32 bytes nonce which is generated by the hardware wallet to avoid replay attacks.
It needs to be base 64 URL encoded before being sent to the /swap endpoint.

completeExchange

This method will need you to provide, among other things, 2 important parameters:

  • payload: it is the base64 URL encoded result of your call to the /swap/payload endpoints.
  • signature: it is the base64 URL encoded result of your JWS signature of the previous payload.

Here is a little diagram to explain how the payload and its signature are generated: Payload and Payload Signature generation diagram

  • payload: the trade parameters are assembled in a protobuf message, via the /swap/payload endpoint. Then, with base64 encoding we get the payload field.
  • signature: trom the binary encoding of the previous protobuf (Byte Array), we sign it with ES256 and the provider’s private key to get a Signature Byte Array. Finally, with base64 encoding we get the signature.

Test your LiveApp

Thanks to the Developer Mode and the debug-app, you can easily test your integration inside Ledger Live environment.
If you need more info, please check our How to - Test tutorial. You should find everything you need there.


Did you find this page helpful?


How would you improve this page for developers?



Getting Started
Theme Features
Customization

Swap