Skip to content

Ledger Communication

Petar Baykov edited this page Jul 31, 2019 · 19 revisions

Ledger Communication flow

Because extensions have limited access to browser features, there's no easy way to interact wth the Ledger Hardware wallet from the Waellet extension. Waellet implements a workaround to those restrictions by injecting an iframe to the pages of the extension (which is hosted here)

The iframe is allowed to interact with the Ledger device (since U2F requires SSL and the iframe is hosted under https) using the library from LedgerJS hw-transport-u2f and æternity ledger app api library and establishes a two-way communication channel with the extension via postMessage.

The flow goes like this:

  1. Iframe is injected in Waellet
  2. When extension need to request ledger, postmessage to the iframe is send. Also message listener is registered in the extension to wait response from iframe
  3. Iframe handles the request and sends postmessage to extension (parent window)
  4. Promise is resolved with data send from the ledger device

Examples of Leger Bridge methods which send messages to iframe

  • Method for sending message to iframe and wait for response
_sendMessage (msg, cb) {
    msg.target = 'LEDGER-IFRAME'
    this.iframe.contentWindow.postMessage(msg, '*')
    window.addEventListener('message', ({ origin, data }) => {
        if (origin !== this._getOrigin()) return false
        if (data && data.action && data.action === `${msg.action}-reply`) {
            cb(data)
        }
    })
}
  • Method for getting address from the ledger device
getAddress(accountIdx) {
    return new Promise((resolve, reject) => {
        this._sendMessage({
            action: 'ledger-get-address',
            params: {
                accountIdx
            },
        },
        ({success, payload}) => {
            if (success) {
                resolve(payload)
            } else {
                reject(payload.error || 'Unknown error')
            }
        })
    })
}
  • Method for signing tx from ledger device
signTransaction(accountIdx,tx,networkId) {
    return new Promise((resolve, reject) => {
        this._sendMessage({
            action: 'ledger-sign-transaction',
            params: {
                accountIdx,
                tx,
                networkId
            },
        },
        ({success, payload}) => {
            if (success) {
                resolve(payload)
            } else {
                reject(payload.error || 'Unknown error')
            }
        })
    })
}
Clone this wiki locally