diff --git a/js/src/3rdparty/ledger/index.js b/js/src/3rdparty/ledger/index.js
new file mode 100644
index 000000000..332d431dd
--- /dev/null
+++ b/js/src/3rdparty/ledger/index.js
@@ -0,0 +1,25 @@
+// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
+// This file is part of Parity.
+
+// Parity is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity. If not, see .
+
+import Ledger3 from './vendor/ledger3';
+import LedgerEth from './vendor/ledger-eth';
+
+export function create () {
+ const ledger = new Ledger3('w0w');
+ const app = new LedgerEth(ledger);
+
+ return app;
+}
diff --git a/js/src/3rdparty/ledger/vendor/README.md b/js/src/3rdparty/ledger/vendor/README.md
new file mode 100644
index 000000000..a44c3521b
--- /dev/null
+++ b/js/src/3rdparty/ledger/vendor/README.md
@@ -0,0 +1,11 @@
+# Description
+
+Vendor files (c) 2016 [Ledger](https://github.com/LedgerHQ) for [Ledger Nano-S](https://www.ledgerwallet.com/) integration
+
+# Origin
+
+Files originally created via [https://github.com/kvhnuke/etherwallet/pull/248/files](https://github.com/kvhnuke/etherwallet/pull/248/files)
+
+# License
+
+Files in this directory is licensed under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) by their original author
diff --git a/js/src/3rdparty/ledger/vendor/ledger-eth.js b/js/src/3rdparty/ledger/vendor/ledger-eth.js
new file mode 100644
index 000000000..80ff0d0a6
--- /dev/null
+++ b/js/src/3rdparty/ledger/vendor/ledger-eth.js
@@ -0,0 +1,166 @@
+/********************************************************************************
+* Ledger Communication toolkit
+* (c) 2016 Ledger
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+********************************************************************************/
+
+/* eslint-disable */
+
+'use strict';
+
+var LedgerEth = function(comm) {
+ this.comm = comm;
+}
+
+LedgerEth.splitPath = function(path) {
+ var result = [];
+ var components = path.split('/');
+ components.forEach(function (element, index) {
+ var number = parseInt(element, 10);
+ if (isNaN(number)) {
+ return;
+ }
+ if ((element.length > 1) && (element[element.length - 1] == "'")) {
+ number += 0x80000000;
+ }
+ result.push(number);
+ });
+ return result;
+}
+
+// callback is function(response, error)
+LedgerEth.prototype.getAddress = function(path, callback, boolDisplay, boolChaincode) {
+ var splitPath = LedgerEth.splitPath(path);
+ var buffer = new Buffer(5 + 1 + splitPath.length * 4);
+ buffer[0] = 0xe0;
+ buffer[1] = 0x02;
+ buffer[2] = (boolDisplay ? 0x01 : 0x00);
+ buffer[3] = (boolChaincode ? 0x01 : 0x00);
+ buffer[4] = 1 + splitPath.length * 4;
+ buffer[5] = splitPath.length;
+ splitPath.forEach(function (element, index) {
+ buffer.writeUInt32BE(element, 6 + 4 * index);
+ });
+ var self = this;
+ var localCallback = function(response, error) {
+ if (typeof error != "undefined") {
+ callback(undefined, error);
+ }
+ else {
+ var result = {};
+ response = new Buffer(response, 'hex');
+ var sw = response.readUInt16BE(response.length - 2);
+ if (sw != 0x9000) {
+ callback(undefined, "Invalid status " + sw.toString(16));
+ return;
+ }
+ var publicKeyLength = response[0];
+ var addressLength = response[1 + publicKeyLength];
+ result['publicKey'] = response.slice(1, 1 + publicKeyLength).toString('hex');
+ result['address'] = "0x" + response.slice(1 + publicKeyLength + 1, 1 + publicKeyLength + 1 + addressLength).toString('ascii');
+ if (boolChaincode) {
+ result['chainCode'] = response.slice(1 + publicKeyLength + 1 + addressLength, 1 + publicKeyLength + 1 + addressLength + 32).toString('hex');
+ }
+ callback(result);
+ }
+ };
+ this.comm.exchange(buffer.toString('hex'), localCallback);
+}
+
+// callback is function(response, error)
+LedgerEth.prototype.signTransaction = function(path, rawTxHex, callback) {
+ var splitPath = LedgerEth.splitPath(path);
+ var offset = 0;
+ var rawTx = new Buffer(rawTxHex, 'hex');
+ var apdus = [];
+ while (offset != rawTx.length) {
+ var maxChunkSize = (offset == 0 ? (150 - 1 - splitPath.length * 4) : 150)
+ var chunkSize = (offset + maxChunkSize > rawTx.length ? rawTx.length - offset : maxChunkSize);
+ var buffer = new Buffer(offset == 0 ? 5 + 1 + splitPath.length * 4 + chunkSize : 5 + chunkSize);
+ buffer[0] = 0xe0;
+ buffer[1] = 0x04;
+ buffer[2] = (offset == 0 ? 0x00 : 0x80);
+ buffer[3] = 0x00;
+ buffer[4] = (offset == 0 ? 1 + splitPath.length * 4 + chunkSize : chunkSize);
+ if (offset == 0) {
+ buffer[5] = splitPath.length;
+ splitPath.forEach(function (element, index) {
+ buffer.writeUInt32BE(element, 6 + 4 * index);
+ });
+ rawTx.copy(buffer, 6 + 4 * splitPath.length, offset, offset + chunkSize);
+ }
+ else {
+ rawTx.copy(buffer, 5, offset, offset + chunkSize);
+ }
+ apdus.push(buffer.toString('hex'));
+ offset += chunkSize;
+ }
+ var self = this;
+ var localCallback = function(response, error) {
+ if (typeof error != "undefined") {
+ callback(undefined, error);
+ }
+ else {
+ response = new Buffer(response, 'hex');
+ var sw = response.readUInt16BE(response.length - 2);
+ if (sw != 0x9000) {
+ callback(undefined, "Invalid status " + sw.toString(16));
+ return;
+ }
+ if (apdus.length == 0) {
+ var result = {};
+ result['v'] = response.slice(0, 1).toString('hex');
+ result['r'] = response.slice(1, 1 + 32).toString('hex');
+ result['s'] = response.slice(1 + 32, 1 + 32 + 32).toString('hex');
+ callback(result);
+ }
+ else {
+ self.comm.exchange(apdus.shift(), localCallback);
+ }
+ }
+ };
+ self.comm.exchange(apdus.shift(), localCallback);
+}
+
+// callback is function(response, error)
+LedgerEth.prototype.getAppConfiguration = function(callback) {
+ var buffer = new Buffer(5);
+ buffer[0] = 0xe0;
+ buffer[1] = 0x06;
+ buffer[2] = 0x00;
+ buffer[3] = 0x00;
+ buffer[4] = 0x00;
+ var localCallback = function(response, error) {
+ if (typeof error != "undefined") {
+ callback(undefined, error);
+ }
+ else {
+ response = new Buffer(response, 'hex');
+ var result = {};
+ var sw = response.readUInt16BE(response.length - 2);
+ if (sw != 0x9000) {
+ callback(undefined, "Invalid status " + sw.toString(16));
+ return;
+ }
+ result['arbitraryDataEnabled'] = (response[0] & 0x01);
+ result['version'] = "" + response[1] + '.' + response[2] + '.' + response[3];
+ callback(result);
+ }
+ };
+ this.comm.exchange(buffer.toString('hex'), localCallback);
+}
+
+module.exports = LedgerEth;
+
+/* eslint-enable */
diff --git a/js/src/3rdparty/ledger/vendor/ledger3.js b/js/src/3rdparty/ledger/vendor/ledger3.js
new file mode 100644
index 000000000..9601279ad
--- /dev/null
+++ b/js/src/3rdparty/ledger/vendor/ledger3.js
@@ -0,0 +1,72 @@
+/********************************************************************************
+* Ledger Communication toolkit
+* (c) 2016 Ledger
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+********************************************************************************/
+
+/* eslint-disable */
+
+'use strict';
+
+var Ledger3 = function(scrambleKey, timeoutSeconds) {
+ this.scrambleKey = new Buffer(scrambleKey, 'ascii');
+ this.timeoutSeconds = timeoutSeconds;
+}
+
+Ledger3.wrapApdu = function(apdu, key) {
+ var result = new Buffer(apdu.length);
+ for (var i=0; i