diff --git a/README.md b/README.md
index 769b8950..adc394cb 100644
--- a/README.md
+++ b/README.md
@@ -38,6 +38,9 @@ Also, make sure that you close Ledger Live or any other apps that might be using
Add udev rules
`wget -q -O - https://raw.githubusercontent.com/LedgerHQ/udev-rules/master/add_udev_rules.sh | sudo bash`
+### Ledger on Latest Chrome browser
+If you're experiencing issues connecting your Ledger device open the following url chrome://flags#new-usb-backend in Chrome browser and disable it. Alternatively you can try Chromium or Brave browsers.
+
## Build/compile issues
If you are experiencing build issues that lead to minify errors add required modules to [config-overrides.js](https://github.com/pbca26/hw-kmd-wallet/blob/master/config-overrides.js#L19) file.
diff --git a/electron/main.js b/electron/main.js
index b2f80327..3cf5cfc8 100755
--- a/electron/main.js
+++ b/electron/main.js
@@ -172,32 +172,32 @@ function createWindow() {
mainWindow = null;
});
- ipcMain.on('getAddress', (e, derivationPath) => {
+ ipcMain.on('getAddress', (e, {ruid, derivationPath}) => {
console.log(derivationPath);
if (mainWindow) {
getAddress(derivationPath, false).then(result => {
- mainWindow.webContents.send('getAddress', result);
+ mainWindow.webContents.send('getAddress', {ruid, result});
});
}
});
- ipcMain.on('createPaymentTransactionNew', (e, txData) => {
+ ipcMain.on('createPaymentTransactionNew', (e, {ruid, txData}) => {
console.log(txData);
if (mainWindow) {
createPaymentTransactionNew(txData).then(result => {
- mainWindow.webContents.send('createPaymentTransactionNew', result);
+ mainWindow.webContents.send('createPaymentTransactionNew', {ruid, result});
});
}
});
- ipcMain.on('splitTransaction', (e, txData) => {
+ ipcMain.on('splitTransaction', (e, {ruid, txData}) => {
console.log(txData);
if (mainWindow) {
splitTransaction(txData).then(result => {
- mainWindow.webContents.send('splitTransaction', result);
+ mainWindow.webContents.send('splitTransaction', {ruid, result});
});
}
});
diff --git a/src/App.js b/src/App.js
index fabf407d..8f5c4fea 100755
--- a/src/App.js
+++ b/src/App.js
@@ -34,7 +34,7 @@ import {
} from './lib/blockchain';
import accountDiscovery from './lib/account-discovery';
import blockchain from './lib/blockchain';
-import apiEndpoints from './lib/insight-endpoints';
+import apiEndpoints from './lib/coins';
import getKomodoRewards from './lib/get-komodo-rewards';
import {osName} from 'react-device-detect';
import {
@@ -135,34 +135,36 @@ class App extends React.Component {
}
checkExplorerEndpoints = async () => {
- const getInfoRes = await Promise.all(apiEndpoints[this.state.coin].map((value, index) => {
+ const getInfoRes = await Promise.all(apiEndpoints[this.state.coin].api.map((value, index) => {
return getInfo(value);
}));
let isExplorerEndpointSet = false;
console.warn('checkExplorerEndpoints', getInfoRes);
- for (let i = 0; i < apiEndpoints[this.state.coin].length; i++) {
+ for (let i = 0; i < apiEndpoints[this.state.coin].api.length; i++) {
if (getInfoRes[i] &&
getInfoRes[i].hasOwnProperty('info') &&
getInfoRes[i].info.hasOwnProperty('version')) {
- console.warn('set api endpoint to ' + apiEndpoints[this.state.coin][i]);
- setExplorerUrl(apiEndpoints[this.state.coin][i]);
+ console.warn('set api endpoint to ' + apiEndpoints[this.state.coin].api[i]);
+ setExplorerUrl(apiEndpoints[this.state.coin].api[i]);
isExplorerEndpointSet = true;
this.setState({
- explorerEndpoint: apiEndpoints[this.state.coin][i],
+ explorerEndpoint: apiEndpoints[this.state.coin].api[i],
});
break;
}
}
- if (!isExplorerEndpointSet) {
- this.setState({
- explorerEndpoint: false,
- });
- }
+ setTimeout(() => {
+ if (!isExplorerEndpointSet) {
+ this.setState({
+ explorerEndpoint: false,
+ });
+ }
+ }, 50);
};
resetState = () => {
diff --git a/src/Transactions.js b/src/Transactions.js
index 6cd3f46c..e9129f39 100644
--- a/src/Transactions.js
+++ b/src/Transactions.js
@@ -1,5 +1,9 @@
import React from 'react';
-import explorerLink from './lib/explorer-link';
+import explorerLink from './lib/coins';
+import {
+ isElectron,
+ shell,
+} from './Electron';
const headings = [
'Type',
@@ -36,9 +40,16 @@ const Transactions = ({transactions, coin}) => {
{Number(tx.height) === -1 || Number(tx.height) === 0 ? '' : tx.date}
- {tx.txid}
+ {isElectron &&
+ shell.openExternal(`${explorerLink[coin].explorer}tx/${tx.txid}`)}>{tx.txid}
+ }
+ {!isElectron &&
+ {tx.txid}
+ }
|
))}
diff --git a/src/TxidLink.js b/src/TxidLink.js
index 79760c8e..a9d3b537 100644
--- a/src/TxidLink.js
+++ b/src/TxidLink.js
@@ -1,5 +1,5 @@
import React from 'react';
-import explorerLink from './lib/explorer-link';
+import explorerLink from './lib/coins';
import {
isElectron,
shell,
@@ -9,11 +9,11 @@ const TxidLink = ({txid, coin}) => !isElectron ? (
{txid}
+ href={`${explorerLink[coin].explorer}tx/${txid}`}>{txid}
) : (
shell.openExternal(`${explorerLink[coin]}tx/${txid}`)}>{txid}
+ onClick={() => shell.openExternal(`${explorerLink[coin].explorer}tx/${txid}`)}>{txid}
);
export default TxidLink;
diff --git a/src/lib/coins.js b/src/lib/coins.js
index 4284d3e1..f72d4e53 100644
--- a/src/lib/coins.js
+++ b/src/lib/coins.js
@@ -155,8 +155,9 @@ const coins = {
RICK: {
explorer: 'https://rick.kmd.dev/',
api: [
- 'https://rick.kmd.dev/insight-api-komodo/',
+ 'https://explorer.komodoplatform.com:10000/rick/api/',
'https://rick.explorer.dexstats.info/insight-api-komodo/',
+ 'https://rick.kmd.dev/insight-api-komodo/',
],
},
MORTY: {
@@ -164,6 +165,7 @@ const coins = {
api: [
'https://morty.kmd.dev/insight-api-komodo/',
'https://morty.explorer.dexstats.info/insight-api-komodo/',
+ 'https://explorer.komodoplatform.com:10000/morty/api/',
],
},
VRSC: {
@@ -171,6 +173,7 @@ const coins = {
api: [
'https://explorer.komodoplatform.com:10000/vrsc/api/',
'https://vrsc.explorer.dexstats.info/insight-api-komodo/',
+ 'https://insight.vrsc.0x03.services/insight-api-komodo/',
],
},
// DP: '',
diff --git a/src/lib/explorer-link.js b/src/lib/explorer-link.js
deleted file mode 100644
index 3cf9fb2c..00000000
--- a/src/lib/explorer-link.js
+++ /dev/null
@@ -1,52 +0,0 @@
-const explorers = {
- KMD: 'https://kmd.explorer.dexstats.info/',
- AXO: 'https://axo.explorer.dexstats.info/',
- ETOMIC: 'https://etomic.explorer.dexstats.info/',
- KOIN: 'https://koin.explorer.dexstats.info/',
- MESH: 'https://mesh.explorer.dexstats.info/',
- DEX: 'https://dex.explorer.dexstats.info/',
- SUPERNET: 'https://supernet.explorer.dexstats.info/',
- DION: 'https://explorer.dionpay.com/',
- CCL: 'https://ccl.explorer.dexstats.info/',
- KV: 'https://kv.explorer.dexstats.info/',
- CHAIN: 'https://chain.explorer.dexstats.info/',
- PGT: 'https://pgt.explorer.dexstats.info/',
- MSHARK: 'https://mshark.explorer.dexstats.info/',
- REVS: 'https://revs.explorer.dexstats.info/',
- PANGEA: 'https://pangea.explorer.dexstats.info/',
- JUMBLR: 'https://jumblr.explorer.dexstats.info/',
- BET: 'https://bet.explorer.dexstats.info/',
- CRYPTO: 'https://crypto.explorer.dexstats.info/',
- HODL: 'https://hodl.explorer.dexstats.info/',
- ILN: 'https://explorer.ilien.io/',
- BOTS: 'https://bots.explorer.dexstats.info/',
- MGW: 'https://mgw.explorer.dexstats.info/',
- WLC21: 'https://wlc21.explorer.dexstats.info/',
- COQUICASH: 'https://coquicash.explorer.dexstats.info/',
- BTCH: 'https://btch.explorer.dexstats.info/',
- HUSH3: 'https://hush3.explorer.dexstats.info/',
- NINJA: 'https://ninja.explorer.dexstats.info/',
- SEC: 'https://sec.explorer.dexstats.info/',
- THC: 'https://thc.explorer.dexstats.info/',
- KMDICE: 'https://kmdice.explorer.dexstats.info/',
- ZEXO: 'https://zex.explorer.dexstats.info/',
- KSB: 'https://ksb.explorer.dexstats.info/',
- OUR: 'https://our.explorer.dexstats.info/',
- MCL: 'https://mcl.explorer.dexstats.info/',
- RFOX: 'https://rfox.explorer.dexstats.info/',
- LABS: 'https://labs.explorer.dexstats.info/',
- VOTE2020: 'https://vote2020.explorer.dexstats.info/',
- RICK: 'https://rick.kmd.dev/',
- MORTY: 'https://morty.kmd.dev/',
- VRSC: 'https://vrsc.explorer.dexstats.info/',
- ZILLA: 'https://zilla.explorer.dexstats.info/',
- OOT: 'https://oot.explorer.dexstats.info/',
- // DP: '',
- // SHARK: '',
- // EQL: '',
- // PIZZA: '',
- // BEER: '',
- // DSEC: '',
-};
-
-export default explorers;
\ No newline at end of file
diff --git a/src/lib/insight-endpoints.js b/src/lib/insight-endpoints.js
deleted file mode 100644
index 61ff93cc..00000000
--- a/src/lib/insight-endpoints.js
+++ /dev/null
@@ -1,69 +0,0 @@
-// TODO: refactor as coin object
-import {sortObject} from './sort';
-
-const apiEndpoints = {
- KMD: [
- 'https://explorer.komodoplatform.com:10000/kmd/api/',
- 'https://kmd.explorer.dexstats.info/insight-api-komodo/'
- ],
- AXO: ['https://axo.explorer.dexstats.info/insight-api-komodo/'],
- ETOMIC: ['https://etomic.explorer.dexstats.info/insight-api-komodo/'],
- KOIN: ['https://koin.explorer.dexstats.info/insight-api-komodo/'],
- MESH: ['https://mesh.explorer.dexstats.info/insight-api-komodo/'],
- DEX: ['https://dex.explorer.dexstats.info/insight-api-komodo/'],
- SUPERNET: ['https://supernet.explorer.dexstats.info/insight-api-komodo/'],
- DION: ['https://explorer.dionpay.com/insight-api-komodo/'],
- CCL: ['https://ccl.explorer.dexstats.info/insight-api-komodo/'],
- KV: ['https://kv.explorer.dexstats.info/insight-api-komodo/'],
- CHAIN: ['https://chain.explorer.dexstats.info/insight-api-komodo/'],
- PGT: ['https://pgt.explorer.dexstats.info/insight-api-komodo/'],
- MSHARK: ['https://mshark.explorer.dexstats.info/insight-api-komodo/'],
- REVS: ['https://revs.explorer.dexstats.info/insight-api-komodo/'],
- PANGEA: ['https://pangea.explorer.dexstats.info/insight-api-komodo/'],
- JUMBLR: ['https://jumblr.explorer.dexstats.info/insight-api-komodo/'],
- BET: ['https://bet.explorer.dexstats.info/insight-api-komodo/'],
- CRYPTO: ['https://crypto.explorer.dexstats.info/insight-api-komodo/'],
- HODL: ['https://hodl.explorer.dexstats.info/insight-api-komodo/'],
- ILN: ['https://explorer.ilien.io/insight-api-komodo/'],
- BOTS: ['https://bots.explorer.dexstats.info/insight-api-komodo/'],
- MGW: ['https://mgw.explorer.dexstats.info/insight-api-komodo/'],
- WLC21: ['https://wlc21.explorer.dexstats.info/insight-api-komodo/'],
- COQUICASH: ['https://coquicash.explorer.dexstats.info/insight-api-komodo/'],
- BTCH: ['https://btch.explorer.dexstats.info/insight-api-komodo/'],
- HUSH3: ['https://hush3.explorer.dexstats.info/insight-api-komodo/'],
- NINJA: ['https://ninja.explorer.dexstats.info/insight-api-komodo/'],
- SEC: ['https://sec.explorer.dexstats.info/insight-api-komodo/'],
- THC: ['https://thc.explorer.dexstats.info/insight-api-komodo/'],
- KMDICE: ['https://kmdice.explorer.dexstats.info/insight-api-komodo/'],
- ZEXO: ['https://zexo.explorer.dexstats.info/insight-api-komodo/'],
- KSB: ['https://ksb.explorer.dexstats.info/insight-api-komodo/'],
- OUR: ['https://our.explorer.dexstats.info/insight-api-komodo/'],
- MCL: ['https://mcl.explorer.dexstats.info/insight-api-komodo/'],
- RFOX: ['https://rfox.explorer.dexstats.info/insight-api-komodo/'],
- LABS: ['https://labs.explorer.dexstats.info/insight-api-komodo/'],
- VOTE2020: ['https://vote2020.explorer.dexstats.info/insight-api-komodo/'],
- RICK: [
- 'https://rick.kmd.dev/insight-api-komodo/',
- 'https://rick.explorer.dexstats.info/insight-api-komodo/'
- ],
- MORTY: [
- 'https://morty.kmd.dev/insight-api-komodo/',
- 'https://morty.explorer.dexstats.info/insight-api-komodo/'
- ],
- VRSC: [
- 'https://explorer.komodoplatform.com:10000/vrsc/api/',
- 'https://vrsc.explorer.dexstats.info/insight-api-komodo/'
- ]
- // EQL: [],
- // DP: [],
- // PIZZA: [],
- // BEER: [],
- // DSEC: [],
- // SHARK: [],
- /* coins below need special handling due to no overwinter support
- ZILLA: ['https://zilla.explorer.dexstats.info/insight-api-komodo/'],
- OOT: ['https://oot.explorer.dexstats.info/insight-api-komodo/'],
- */
-};
-
-export default sortObject(apiEndpoints);
\ No newline at end of file
diff --git a/src/lib/ledger-ipc-wrapper.js b/src/lib/ledger-ipc-wrapper.js
index 006c6b04..d20fbe72 100644
--- a/src/lib/ledger-ipc-wrapper.js
+++ b/src/lib/ledger-ipc-wrapper.js
@@ -1,17 +1,70 @@
-import {ipcRenderer} from '../Electron';
+import {
+ ipcRenderer,
+ isElectron,
+} from '../Electron';
+
+let data = {};
+let ruid = 0;
+let intervals = {};
+let pendingCalls = {};
+
+// return data only when it was sent over from ipc main proc
+const getData = (ruid, payload) => {
+ return new Promise((resolve, reject) => {
+ if (!data[ruid]) {
+ console.warn(`ledger data ruid ${ruid} not available yet, set interval`, ruid);
+
+ intervals[ruid] = setInterval((ruid) => {
+ if (data[ruid]) {
+ console.warn(`ledger data ruid ${ruid} available, clear interval`, data[ruid]);
+ clearInterval(intervals[ruid]);
+ delete pendingCalls[ruid];
+ resolve(data[ruid] === 'false' ? false : data[ruid]);
+ } else {
+ pendingCalls[ruid] = payload;
+ }
+ }, 100, ruid);
+ } else {
+ console.warn(`ledger data ruid ${ruid} available`, data[ruid]);
+ delete pendingCalls[ruid];
+ resolve(data[ruid] === 'false' ? false : data[ruid]);
+ }
+ });
+};
+
+if (isElectron) {
+ ipcRenderer.on('getAddress', (event, arg) => {
+ console.warn('getAddress arg', arg);
+ console.warn('arg.bitcoinAddress', arg);
+ if (arg === -777) data[arg.ruid] = 'false';
+ else data[arg.ruid] = arg.result;
+ });
+
+ ipcRenderer.on('createPaymentTransactionNew', (event, arg) => {
+ console.warn('createPaymentTransactionNew arg', arg);
+ if (arg === -777) data[arg.ruid] = 'false';
+ else data[arg.ruid] = arg.result;
+ });
+
+ ipcRenderer.on('splitTransaction', (event, arg) => {
+ console.warn('splitTransaction arg', arg);
+ if (arg === -777) data[arg.ruid] = 'false';
+ else data[arg.ruid] = arg.result;
+ });
+}
// wrap ledger methods using ipc renderer
const getDevice = async () => {
return {
getWalletPublicKey: (derivationPath) => {
- return new Promise((resolve, reject) => {
- ipcRenderer.on('getAddress', (event, arg) => {
- console.warn('getAddress arg', arg);
- console.warn('arg.bitcoinAddress', arg.bitcoinAddress);
- if (arg === -777) resolve(false);
- resolve(arg);
- });
- ipcRenderer.send('getAddress', derivationPath);
+ console.warn(`ledger getWalletPublicKey`);
+ ruid++;
+ ipcRenderer.send('getAddress', {derivationPath, ruid});
+
+ return new Promise(async(resolve, reject) => {
+ const _data = await getData(ruid);
+ console.warn('ledger getAddress ready', _data);
+ resolve(_data);
});
},
createPaymentTransactionNew: (
@@ -26,24 +79,25 @@ const getDevice = async () => {
additionals,
expiryHeight,
) => {
- return new Promise((resolve, reject) => {
- ipcRenderer.on('createPaymentTransactionNew', (event, arg) => {
- console.warn('createPaymentTransactionNew arg', arg);
- if (arg === -777) resolve(false);
- resolve(arg);
- });
- ipcRenderer.send('createPaymentTransactionNew', {
- inputs,
- associatedKeysets,
- changePath,
- outputScript,
- lockTime,
- sigHashType,
- segwit,
- initialTimestamp,
- additionals,
- expiryHeight,
- });
+ console.warn(`ledger createPaymentTransactionNew`);
+ ruid++;
+ ipcRenderer.send('createPaymentTransactionNew', {txData: {
+ inputs,
+ associatedKeysets,
+ changePath,
+ outputScript,
+ lockTime,
+ sigHashType,
+ segwit,
+ initialTimestamp,
+ additionals,
+ expiryHeight,
+ }, ruid});
+
+ return new Promise(async(resolve, reject) => {
+ const _data = await getData(ruid);
+ console.warn('ledger createPaymentTransactionNew ready', _data);
+ resolve(_data);
});
},
splitTransaction: (
@@ -53,19 +107,20 @@ const getDevice = async () => {
hasExtraData,
additionals,
) => {
- return new Promise((resolve, reject) => {
- ipcRenderer.on('splitTransaction', (event, arg) => {
- console.warn('splitTransaction arg', arg);
- if (arg === -777) resolve(false);
- resolve(arg);
- });
- ipcRenderer.send('splitTransaction', {
- transactionHex,
- isSegwitSupported,
- hasTimestamp,
- hasExtraData,
- additionals,
- });
+ console.warn(`ledger splitTransaction`);
+ ruid++;
+ ipcRenderer.send('splitTransaction', {txData: {
+ transactionHex,
+ isSegwitSupported,
+ hasTimestamp,
+ hasExtraData,
+ additionals,
+ }, ruid});
+
+ return new Promise(async(resolve, reject) => {
+ const _data = await getData(ruid);
+ console.warn('ledger splitTransaction ready', _data);
+ resolve(_data);
});
},
close: () => {},