xumm-sdk
    TypeScript icon, indicating that this package has built-in type declarations

    0.6.0 • Public • Published

    XUMM SDK (JS/TS) npm version GitHub Actions NodeJS status GitHub Actions Deno status

    Interact with the XUMM SDK from Javascript / Typescript environments.

    Please note! The XUMM SDK (XUMM API in general) is for BACKEND USE only. Please DO NOT use your API credentials in a FRONTEND environment.

    To implement the XUMM SKD (or XUMM API directly) in your own web project, make sure your frontend calls your own backend, where the follow up communication with the XUMM SDK (or XUMM API) will take place. Your XUMM credentials should never be publicly available.

    How to use the XUMM SDK

    Get the SDK straight from npm: npm install xumm-sdk. The SDK is also available for Deno (XUMM SDK Deno Readme).

    Initialize the SDK in Javascript:

    const {XummSdk} = require('xumm-sdk')

    ... or in Typescript:

    import {XummSdk} from 'xumm-sdk'
    // Or with types:
    //   import {XummSdk, XummTypes} from 'xumm-sdk'

    Now continue by constructing the XummSdk object:

    const Sdk = new XummSdk()
    // Or with manually provided credentials (instead of using dotenv):
    //   const Sdk = new XummSdk('someAppKey', 'someAppSecret')

    Credentials

    The SDK will look in your environment or dotenv file (.env) for the XUMM_APIKEY and XUMM_APISECRET values. A .env.sample file is provided in this repository. A sample dotenv file looks like this. Alternatively you can provide your XUMM API Key & Secret by passing them to the XummSdk constructor. If both your environment and the SDK constructor contain credentials, the values provided to the constructor will be used.

    Create your app and get your XUMM API credentials at the XUMM Developer Console:

    More information about the XUMM API, payloads, the API workflow, sending Push notifications, etc. please check the XUMM API Docs:

    Methods & params (+ samples)

    After constructing the SDK, you can call the methods:

    • Sdk.* for the helper methods (see below)
    • Sdk.payload.* to get/update/create payloads for users to sign
    • Sdk.storage.* for your XUMM app storage (to store meta info for headless applications)

    Please note all snippets below assume you constructed the XUMM SDK into the Sdk constant, as the How to use the XUMM SDK section outlines.

    Helper methods

    Sdk.ping()

    The ping method allows you to verify API access (valid credentials) and returns some info on your XUMM APP:

    const pong = await Sdk.ping()

    Returns <ApplicationDetails>:

    {
      quota: {},
      application: {
        uuidv4: '00000000-1111-2222-3333-aaaaaaaaaaaa',
        name: 'My XUMM APP',
        webhookurl: '',
        disabled: 0
      },
      call: { uuidv4: 'bbbbbbbb-cccc-dddd-eeee-111111111111' }
    }
    Sdk.getCuratedAssets()

    The getCuratedAssets method allows you to get the list of trusted issuers and IOU's. This is the same list used to populate the "Add Asset" button at the XUMM home screan.

    const curatedAssets = await Sdk.getCuratedAssets()

    Returns <CuratedAssetsResponse>:

    {
      curatedAssets: {
        issuers: [ 'Bitstamp', 'GateHub' ],
        currencies: [ 'USD', 'BTC', 'EUR', 'ETH' ],
        details: {
          Bitstamp: [Object],
          GateHub: [Object]
        }
      }
    }
    Sdk.getKycStatus()

    The getKycStatus return the KYC status of a user based on a user_token, issued after the user signed a Sign Request (from your app) before (see Payloads - Intro).

    If a user token specified is invalid, revoked, expired, etc. the method will always return NONE, just like when a user didn't go through KYC. You cannot distinct a non-KYC'd user from an invalid token.

    Alternatively, KYC status can be retrieved for an XPRL account address: the address selected in XUMM when the session KYC was initiated by.

    const kycStatus = await Sdk.getKycStatus('00000000-0000-0000-0000-000000000000')

    ... or using an account address:

    const kycStatus = await Sdk.getKycStatus('rwu1dgaUq8DCj3ZLFXzRbc1Aco5xLykMMQ')

    Returns <keyof PossibleKycStatuses>.

    Notes on KYC information
    • Once an account has successfully completed the XUMM KYC flow, the KYC flag will be applied to the account even if the identity document used to KYC expired. The flag shows that the account was once KYC'd by a real person with a real identity document.
    • Please note that the KYC flag provided by XUMM can't be seen as a "all good, let's go ahead" flag: it should be used as one of the data points to determine if an account can be trusted. There are situations where the KYC flag is still true, but an account can no longer be trusted. Eg. when account keys are compromised and the account is now controlled by a 3rd party. While unlikely, depending on the level of trust required for your application you may want to mitigate against these kinds of fraud.
    Sdk.getTransaction()

    The getTransaction method allows you to get the transaction outcome (mainnet) live from the XRP ledger, as fetched for you by the XUMM backend.

    Note: it's best to retrieve these results yourself instead of relying on the XUMM platform to get live XRPL transaction information! You can use the xrpl-txdata package to do this:
    npm version

    const txInfo = await Sdk.getTransaction(txHash)

    Returns: <XrplTransaction>](https://github.com/XRPL-Labs/XUMM-SDK/blob/master/src/types/Meta/XrplTransaction.ts)

    App Storage

    App Storage allows you to store a JSON object at the XUMM API platform, containing max 60KB of data. Your XUMM APP storage is stored at the XUMM API backend, meaning it persists until you overwrite or delete it.

    This data is private, and accessible only with your own API credentials. This private JSON data can be used to store credentials / config / bootstrap info / ... for your headless application (eg. POS device).

    const storageSet = await Sdk.storage.set({name: 'Wietse', age: 32, male: true})
    console.log(storageSet)
    // true
    
    const storageGet = await Sdk.storage.get()
    console.log(storageGet)
    // { name: 'Wietse', age: 32, male: true }
    
    const storageDelete = await Sdk.storage.delete()
    console.log(storageDelete)
    // true
    
    const storageGetAfterDelete = await Sdk.storage.get()
    console.log(storageGetAfterDelete)
    // null

    Payloads

    Intro

    Payloads are the primary reason for the XUMM API (thus this SDK) to exist. The XUMM API Docs explain 'Payloads' like this:

    An XRPL transaction "template" can be posted to the XUMM API. Your transaction tample to sign (so: your "sign request") will be persisted at the XUMM API backend. We now call it a a Payload. XUMM app user(s) can open the Payload (sign request) by scanning a QR code, opening deeplink or receiving push notification and resolve (reject or sign) on their own device.

    A payload can contain an XRPL transaction template. Some properties may be omitted, as they will be added by the XUMM app when a user signs a transaction. A simple payload may look like this:

    {
      txjson: {
        TransactionType : 'Payment',
        Destination : 'rwiETSee2wMz3SBnAG8hkMsCgvGy9LWbZ1',
        Amount: '1337'
      }
    }

    As you can see the payload looks like a regular XRPL transaction, wrapped in an txjson object, omitting the mandatory Account, Fee and Sequence properties. They will be added containing the correct values when the payload is signed by an app user.

    Optionally (besides txjson) a payload can contain these properties (TS definition):

    • options to define payload options like a return URL, expiration, etc.
    • custom_meta to add metadata, user insruction, your own unique ID, ...
    • user_token to push the payload to a user (after obtaining a user specific token)

    A more complex payload could look like this. A reference for payload options & custom meta can be found in the API Docs.

    Instead of providing a txjson transaction, a transaction formatted as HEX blob (string) can be provided in a txblob property.

    Sdk.payload.get
    async Sdk.payload.get (
      payload: string | CreatedPayload,
      returnErrors: boolean = false
    ): Promise<XummPayload | null>

    To get payload details, status and if resolved & signed: results (transaction, transaction hash, etc.) you can get() a payload.

    Note! Please don't use polling! The XUMM API offers Webhooks (configure your Webhook endpoint in the Developer Console) or use a subscription to receive live payload updates (for non-SDK users: Webhooks).

    You can get() a payload by:

    • Payload UUID

      const payload = await Sdk.payload.get('aaaaaaaa-bbbb-cccc-dddd-1234567890ab')
    • Passing a created Payload object (see: Sdk.payload.create)

      const newPayload: XummTypes.CreatedPayload = {txjson: {...}}
      const created = await Sdk.payload.create(newPayload)
      const payload = await Sdk.payload.get(created)

    If a payload can't be fetched (eg. doesn't exist), null will be returned, unless a second param (boolean) is provided to get the SDK to throw an Error in case a payload can't be retrieved:

    await Sdk.payload.get('aaaaaaaa-bbbb-cccc-dddd-1234567890ab', true)
    Sdk.payload.create
    async Sdk.payload.create (
      payload: CreatePayload,
      returnErrors: boolean = false
    ): Promise<CreatedPayload | null>

    To create a payload, a txjson XRPL transaction can be provided. Alternatively, a transaction formatted as HEX blob (string) can be provided in a txblob property. See the intro for more information about payloads. Take a look at the Developer Docs for more information about payloads.

    The response (see: Developer Docs) of a Sdk.payload.create() operation, a <CreatedPayload> object, looks like this:

    {
      "uuid": "1289e9ae-7d5d-4d5f-b89c-18633112ce09",
      "next": {
        "always": "https://xumm.app/sign/1289e9ae-7d5d-4d5f-b89c-18633112ce09",
        "no_push_msg_received": "https://xumm.app/sign/1289e9ae-7d5d-4d5f-b89c-18633112ce09/qr"
      },
      "refs": {
        "qr_png": "https://xumm.app/sign/1289e9ae-7d5d-4d5f-b89c-18633112ce09_q.png",
        "qr_matrix": "https://xumm.app/sign/1289e9ae-7d5d-4d5f-b89c-18633112ce09_q.json",
        "qr_uri_quality_opts": [ "m", "q", "h" ],
        "websocket_status": "wss://xumm.app/sign/1289e9ae-7d5d-4d5f-b89c-18633112ce09"
      },
      "pushed": true
    }

    The next.always URL is the URL to send the end user to, to scan a QR code or automatically open the XUMM app (if on mobile). If a user_token has been provided as part of the payload data provided to Sdk.payload.create(), you can see if the payload has been pushed to the end user. A button "didn't receive a push notification" could then take the user to the next.no_push_msg_received URL. The

    Alternatively user routing / instruction flows can be custom built using the QR information provided in the refs object, and a subscription for live status updates (opened, signed, etc.) using a WebSocket client can be setup by conneting to the refs.websocket_status URL. Please note: this SDK already offers subscriptions. There's no need to setup your own WebSocket client, see Payload subscriptions: live updates. There's more information about the payload workflow and a paylaod lifecycle in the Developer Docs.

    Sdk.payload.cancel
    async Sdk.payload.cancel (
      payload: string | XummPayload | CreatedPayload,
      returnErrors: boolean = false
    ): Promise<DeletedPayload | null>

    To cancel a payload, provide a payload UUID (string), a <XummPayload> (by performing a Sdk.payload.get() first) or a <CreatedPayload> (by using the response of a Sdk.payload.create() call). By cancelling an existing payload, the payload will be marked as expired and can no longer be opened by users.

    Please note: if a user already opened the payload in XUMM APP, the payload cannot be cancelled: the user may still be resolving the payload in the XUMM App, and should have a chance to complete that process.

    A response (generic API types here) looks like:

    {
      result: {
        cancelled: boolean
        reason: XummCancelReason
      }
      meta: XummPayloadMeta
      custom_meta: XummCustomMeta
    }

    Payload subscriptions: live updates

    To subscribe to live payload status updates, the XUMM SDK can setup a WebSocket connection and monitor live status events. Emitted events include:

    • The payload is opened by a XUMM App user (webpage)
    • The payload is opened by a XUMM App user (in the app)
    • Payload expiration updates (remaining time in seconds)
    • The payload was resolved by rejecting
    • The payload was resolved by accepting (signing)

    More information about the status update events & sample event data can be found in the Developer Docs.

    Status updates can be processed by providing a callback function to the Sdk.payload.subscribe() method. Alternatively, the (by the Sdk.payload.subscribe() method) returned raw websocket can be used to listen for WebSocket onmessage events.

    The subscription will be closed by either:

    • Returning non-void in the callback function passed to the Sdk.payload.subscribe() method
    • Manually calling <PayloadSubscription>.resolve() on the object returned by the Sdk.payload.subscribe() method
    Sdk.payload.subscribe
    async Sdk.payload.subscribe (
      payload: string | XummPayload | CreatedPayload,
      callback?: onPayloadEvent
    ): Promise<PayloadSubscription>

    If a callback function is not provided, the subscription will stay active until the <PayloadSubscription>.resolve() method is called manually, eg. based on handling <PayloadSubscription>.websocket.onmessage events.

    When a callback function is provided, for every paylaod specific event the callback function will be called with <SubscriptionCallbackParams>. The <SubscriptionCallbackParams>.data property contains parsed JSON containing event information. Either by calling <SubscriptionCallbackParams>.resolve() or by returning a non-void value in the callback function the subscription will be ended, and the <PayloadSubscription>.resolved promise will resolve with the value returned or passed to the <SubscriptionCallbackParams>.resolve() method.

    Resolving (by returning non-void in the callback or calling resolve() manually) closes the WebSocket client the XUMM SDK sets up 'under the hood'.

    The <PayloadSubscription> object looks like this:

    {
      payload: XummPayload,
      resolved: Promise<unknown> | undefined
      resolve: (resolveData?: unknown) => void
      websocket: WebSocket
    }

    Examples:

    Sdk.payload.createAndSubscribe
    async Sdk.payload.createAndSubscribe (
        payload: CreatePayload,
        callback?: onPayloadEvent
      ): Promise<PayloadAndSubscription>

    The <PayloadAndSubscription> object is basically a <PayloadSubscription> object with the created payload results in the created property:

    All information that applies on Sdk.payload.create() and Sdk.payload.subscribe() applies. Differences are:

    1. The input for a Sdk.payload.createAndSubscribe() call isn't a payload UUID / existing payload, but a paykiad to create.
    2. The response object also contains (<PayloadAndSubscription>.created) the response obtained when creating the payload

    Debugging (logging)

    The XUMM SDK will emit debugging info when invoked with a debug environment variable configured like: DEBUG=xumm-sdk*

    You'll see the XUMM SDK debug messages if you invoke your script instead of this:

    node myApp.js
    

    like this:

    DEBUG=xumm-sdk* node myApp.js
    

    Development

    Please note: you most likely just want to use the XUMM SDK, to do so, fetch the xumm-sdk package from NPM using npm install --save xumm-sdk.

    If you actually want to change/test/develop/build/contribute (to) the source of the XUMM SDK:

    Build

    Please note: at least Typescript version 3.8+ is required!

    To build the code, run tsc. To build automatically on file changes (watch): tsc -w.

    Lint & test

    Lint the code using npm run lint, run tests (jest) using npm run test

    Run development code:

    Build, run, show debug output & watch dist/samples/dev.js, compiled from samples/dev.ts using npm run dev. The samples/dev.ts file is not included by default.

    Here's a sample samples/dev.ts file.

    Install

    npm i xumm-sdk

    DownloadsWeekly Downloads

    68

    Version

    0.6.0

    License

    MIT

    Unpacked Size

    59.6 kB

    Total Files

    59

    Last publish

    Collaborators

    • avatar
    • avatar