Building on the KeepKey-SDK

Highlander
5 min readAug 16, 2023

--

SDK usage

TL:DR

https://www.npmjs.com/package/@keepkey/keepkey-sdk

export const setupKeepKeySDK = async () => {
let serviceKey = window.localStorage.getItem('@app/serviceKey')
let config: any = {
apiKey: serviceKey,
pairingInfo: {
name: 'ShapeShift',
imageUrl: 'https://assets.coincap.io/assets/icons/fox@2x.png',
basePath: 'http://localhost:1646/spec/swagger.json',
url: 'https://private.shapeshift.com',
},
}
let sdk = await KeepKeySdk.create(config)

if (!serviceKey) {
window.localStorage.setItem('@app/serviceKey', config.apiKey)
}
return sdk
}

get a bitcoin address

     let path =
{
symbol: 'BTC',
address_n: [0x80000000 + 44, 0x80000000 + 1, 0x80000000 + 0],
coin: 'Bitcoin',
script_type: 'p2pkh',
showDisplay: false
}

let addressBtc = await sdk.system.info.getPublicKey(path)

signTx

      let hdwalletTxDescription = {
coin: 'Bitcoin',
inputs:inputsSelected,
outputs:outputsFinal,
version: 1,
locktime: 0,
}

//signTx
let signedTxTransfer = await sdk.utxo.utxoSignTransaction(hdwalletTxDescription)

Understanding the KeepKey SDK

Terms:

REST: (REpresentational State Transfer) is an architectural style used for designing distributed systems. It is based on a client-server model, where the client makes requests to the server and the server responds with a representation of the requested resource. REST is used to build public APIs that are easy to use and maintain.

REST: https://restfulapi.net/

Swagger: is an open source software framework used to describe and document RESTful APIs. It provides a simple way for developers to describe the operations, parameters and responses of an API. Swagger also provides interactive documentation, client SDK generation, and testing tools.

More info:

Swagger: https://swagger.io/

Understanding the KeepKey Template

SDK example Repo: https://github.com/keepkey/keepkey-template

Quick get started

npx degit BitHighlander/keepkey-template *your app name*

Topics:

KeepKey: buy a keepkey, Keepkey.com

KeepKey REST api: https://medium.com/@highlander_35968/understanding-the-keepkey-rest-api-f9801b5db220

Swagger: https://swagger.io/

lets get Started:

Import the SDK into your project.

  const onStart = async function () {
try {
const spec = "http://localhost:1646/spec/swagger.json";
const apiKey = localStorage.getItem("apiKey") || "1234";
const config = {
apiKey,
pairingInfo: {
name: "KeepKey-template Demo App",
imageUrl:
"https://pioneers.dev/coins/keepkey.png",
basePath: spec,
url: "http://localhost:1646",
},
};
// init
const sdk = await KeepKeySdk.create(config);
if (config.apiKey !== apiKey)
localStorage.setItem("apiKey", config.apiKey);
};

// onstart get data
useEffect(() => {
onStart();
}, []);

Lets go over the config:

spec: The url hosting the api specification. The keepkey rest api swagger.jon is a formal specification for all the interactions of your keepkey.

apiKey: every new application that requests to communicate with your keepkey will be issues an apiKey. The application must store this apiKey in order to avoid the user needing to re-approve this application for communication.

imageUrl: the dapp should host a image for the user to recognize the dapp on the pairing screen.

url: the url is the domain the dapp is hosted on. KeepKey desktop will remember these URL’s and allow users to return to your dapp from inside keepkey desktop itself. This prevents common attacks related to phishing

Notes on API docs:

View the swagger docs directly:

link: http://localhost:1646/docs

Auth:

Lets talk about auth. this line

      const sdk = await KeepKeySdk.create(config);
if (config.apiKey !== apiKey)
localStorage.setItem("apiKey", config.apiKey);

Note that the config object passed into the keepkey sdk package is mutated. The apiKey issued by the KeepKey desktop application is returned to the sdk package and added to the config.

In this example we set the value into local storage. The ensures that when the user returns to this application they will not be forced to accept a pairing again.

Notes: It’s important to understand an apiKey pairing does not allow an application to spend your money. Every transaction still required user interaction via the physical KeepKey. It only allows pubkey keys to be given to the application as needed to build transactions and report balances. It also allows an application to submit transactions to be signed by the device. Users may revoke these keys at any time, and all communication is logged and auditable via these apiKeys.

Features:

code:

      const featuresKK = await sdk.system.info.getFeatures();

Pubkeys:

We use the SDK to get the publicKey for Dash

let path =
{
symbol: 'DASH',
address_n: [0x80000000 + 44, 0x80000000 + 5, 0x80000000 + 0],
coin: 'Bitcoin',
script_type: 'p2pkh',
showDisplay: false
}

let responsePubkey = await sdk.system.info.getPublicKey(path)
console.log("responsePubkey: ", responsePubkey)
console.log("responsePubkey: ", responsePubkey.xpub)

Note that the path for DASH is 5. as found on https://github.com/satoshilabs/slips/blob/master/slip-0044.md

And Finally we get the xpub for dash returned.

Sign TX:

UTXO example:

          
inputs = [
{
addressNList: [2147483692, 2147483653, 2147483648, 0, 0],
scriptType: "p2pkh",
amount: String(390000),
vout: 0,
txid: "d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882",
tx: input,
},
];
outputs = [
{
address: "1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1",
addressType: "spend",
// scriptType: core.BTCOutputScriptType.PayToAddress,
amount: String(390000 - 10000),
isChange: false,
},
];

input = {
coin: "Bitcoin",
inputs,
outputs,
version: 1,
locktime: 0,
};
// @ts-ignore
console.log("Sign! ", JSON.stringify(input));
console.log("sdk: ", sdk);
console.log("sdk: ", sdk.utxo);
// @ts-ignore
responseSign = await sdk.utxo.utxoSignTransaction(input);

AddressNList: Is the path the pubkey is on

isChange: when marked the KeepKey will verify the address is owned by the Keepkey and display this to the user. This prevent accidental loss of funds by using a change address not owned by your wallet.

scriptType: A script type in the context of Bitcoin refers to a specific set of instructions that dictate how a transaction’s output can be spent. It defines the conditions that need to be met for the recipient to access the funds. One common script type is P2PKH (Pay-to-Public-Key-Hash), where funds can only be spent if the recipient can prove ownership of the private key corresponding to a specific public key hash. Different script types enable various transaction complexities and features on the Bitcoin network.

--

--