From 4697c89064b783dd3c8701057036bb52af4091ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Wed, 9 Mar 2022 16:03:11 +0000 Subject: [PATCH 01/24] feat: format config file --- lib/admin/config.js | 80 +++++++++++------------ lib/blockchain/lightning.js | 0 lib/plugins/wallet/lightning/lightning.js | 0 3 files changed, 40 insertions(+), 40 deletions(-) create mode 100644 lib/blockchain/lightning.js create mode 100644 lib/plugins/wallet/lightning/lightning.js diff --git a/lib/admin/config.js b/lib/admin/config.js index 328cadcf..ab22df32 100644 --- a/lib/admin/config.js +++ b/lib/admin/config.js @@ -13,7 +13,6 @@ const settingsLoader = require('./settings-loader') const configValidate = require('./config-validate') const jsonSchema = require('./lamassu-schema.json') - function fetchSchema () { return _.cloneDeep(jsonSchema) } @@ -148,8 +147,8 @@ const mapLanguage = lang => { const langNameArr = languageRec.lang[code] if (!langNameArr) return null const langName = langNameArr[0] - if (!country) return {code: lang, display: langName} - return {code: lang, display: `${langName} [${country}]`} + if (!country) return { code: lang, display: langName } + return { code: lang, display: `${langName} [${country}]` } } const supportedLanguages = languageRec.supported @@ -159,7 +158,7 @@ const ALL_CRYPTOS = ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH'] const filterAccounts = (data, isDevMode) => { const notAllowed = ['mock-ticker', 'mock-wallet', 'mock-exchange', 'mock-sms', 'mock-id-verify', 'mock-zero-conf'] const filterOut = o => _.includes(o.code, notAllowed) - return isDevMode ? data : {...data, accounts: _.filter(a => !filterOut(a), data.accounts)} + return isDevMode ? data : { ...data, accounts: _.filter(a => !filterOut(a), data.accounts) } } function fetchData () { @@ -167,47 +166,48 @@ function fetchData () { .then(machineList => ({ currencies: massageCurrencies(currencies), cryptoCurrencies: [ - {crypto: 'BTC', display: 'Bitcoin'}, - {crypto: 'ETH', display: 'Ethereum'}, - {crypto: 'LTC', display: 'Litecoin'}, - {crypto: 'DASH', display: 'Dash'}, - {crypto: 'ZEC', display: 'Zcash'}, - {crypto: 'BCH', display: 'Bitcoin Cash'} + { crypto: 'BTC', display: 'Bitcoin' }, + { crypto: 'ETH', display: 'Ethereum' }, + { crypto: 'LTC', display: 'Litecoin' }, + { crypto: 'DASH', display: 'Dash' }, + { crypto: 'ZEC', display: 'Zcash' }, + { crypto: 'BCH', display: 'Bitcoin Cash' }, + { crypto: 'LN', display: 'Lightning Network' } ], languages: languages, countries, accounts: [ - {code: 'bitpay', display: 'Bitpay', class: 'ticker', cryptos: ['BTC', 'BCH']}, - {code: 'kraken', display: 'Kraken', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH']}, - {code: 'bitstamp', display: 'Bitstamp', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'BCH']}, - {code: 'coinbase', display: 'Coinbase', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'BCH', 'ZEC', 'DASH']}, - {code: 'itbit', display: 'itBit', class: 'ticker', cryptos: ['BTC', 'ETH']}, - {code: 'mock-ticker', display: 'Mock (Caution!)', class: 'ticker', cryptos: ALL_CRYPTOS}, - {code: 'bitcoind', display: 'bitcoind', class: 'wallet', cryptos: ['BTC']}, - {code: 'no-layer2', display: 'No Layer 2', class: 'layer2', cryptos: ALL_CRYPTOS}, - {code: 'infura', display: 'Infura', class: 'wallet', cryptos: ['ETH']}, - {code: 'geth', display: 'geth', class: 'wallet', cryptos: ['ETH']}, - {code: 'zcashd', display: 'zcashd', class: 'wallet', cryptos: ['ZEC']}, - {code: 'litecoind', display: 'litecoind', class: 'wallet', cryptos: ['LTC']}, - {code: 'dashd', display: 'dashd', class: 'wallet', cryptos: ['DASH']}, - {code: 'bitcoincashd', display: 'bitcoincashd', class: 'wallet', cryptos: ['BCH']}, - {code: 'bitgo', display: 'BitGo', class: 'wallet', cryptos: ['BTC', 'ZEC', 'LTC', 'BCH', 'DASH']}, - {code: 'bitstamp', display: 'Bitstamp', class: 'exchange', cryptos: ['BTC', 'ETH', 'LTC', 'BCH']}, - {code: 'itbit', display: 'itBit', class: 'exchange', cryptos: ['BTC', 'ETH']}, - {code: 'kraken', display: 'Kraken', class: 'exchange', cryptos: ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH']}, - {code: 'mock-wallet', display: 'Mock (Caution!)', class: 'wallet', cryptos: ALL_CRYPTOS}, - {code: 'no-exchange', display: 'No exchange', class: 'exchange', cryptos: ALL_CRYPTOS}, - {code: 'mock-exchange', display: 'Mock exchange', class: 'exchange', cryptos: ALL_CRYPTOS}, - {code: 'mock-sms', display: 'Mock SMS', class: 'sms'}, - {code: 'mock-id-verify', display: 'Mock ID verifier', class: 'idVerifier'}, - {code: 'twilio', display: 'Twilio', class: 'sms'}, - {code: 'mailgun', display: 'Mailgun', class: 'email'}, - {code: 'all-zero-conf', display: 'Always 0-conf', class: 'zeroConf', cryptos: ['BTC', 'ZEC', 'LTC', 'DASH', 'BCH']}, - {code: 'no-zero-conf', display: 'Always 1-conf', class: 'zeroConf', cryptos: ALL_CRYPTOS}, - {code: 'blockcypher', display: 'Blockcypher', class: 'zeroConf', cryptos: ['BTC']}, - {code: 'mock-zero-conf', display: 'Mock 0-conf', class: 'zeroConf', cryptos: ['BTC', 'ZEC', 'LTC', 'DASH', 'BCH', 'ETH']} + { code: 'bitpay', display: 'Bitpay', class: 'ticker', cryptos: ['BTC', 'BCH'] }, + { code: 'kraken', display: 'Kraken', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH'] }, + { code: 'bitstamp', display: 'Bitstamp', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'BCH'] }, + { code: 'coinbase', display: 'Coinbase', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'BCH', 'ZEC', 'DASH'] }, + { code: 'itbit', display: 'itBit', class: 'ticker', cryptos: ['BTC', 'ETH'] }, + { code: 'mock-ticker', display: 'Mock (Caution!)', class: 'ticker', cryptos: ALL_CRYPTOS }, + { code: 'bitcoind', display: 'bitcoind', class: 'wallet', cryptos: ['BTC'] }, + { code: 'no-layer2', display: 'No Layer 2', class: 'layer2', cryptos: ALL_CRYPTOS }, + { code: 'infura', display: 'Infura', class: 'wallet', cryptos: ['ETH'] }, + { code: 'geth', display: 'geth', class: 'wallet', cryptos: ['ETH'] }, + { code: 'zcashd', display: 'zcashd', class: 'wallet', cryptos: ['ZEC'] }, + { code: 'litecoind', display: 'litecoind', class: 'wallet', cryptos: ['LTC'] }, + { code: 'dashd', display: 'dashd', class: 'wallet', cryptos: ['DASH'] }, + { code: 'bitcoincashd', display: 'bitcoincashd', class: 'wallet', cryptos: ['BCH'] }, + { code: 'bitgo', display: 'BitGo', class: 'wallet', cryptos: ['BTC', 'ZEC', 'LTC', 'BCH', 'DASH'] }, + { code: 'bitstamp', display: 'Bitstamp', class: 'exchange', cryptos: ['BTC', 'ETH', 'LTC', 'BCH'] }, + { code: 'itbit', display: 'itBit', class: 'exchange', cryptos: ['BTC', 'ETH'] }, + { code: 'kraken', display: 'Kraken', class: 'exchange', cryptos: ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH'] }, + { code: 'mock-wallet', display: 'Mock (Caution!)', class: 'wallet', cryptos: ALL_CRYPTOS }, + { code: 'no-exchange', display: 'No exchange', class: 'exchange', cryptos: ALL_CRYPTOS }, + { code: 'mock-exchange', display: 'Mock exchange', class: 'exchange', cryptos: ALL_CRYPTOS }, + { code: 'mock-sms', display: 'Mock SMS', class: 'sms' }, + { code: 'mock-id-verify', display: 'Mock ID verifier', class: 'idVerifier' }, + { code: 'twilio', display: 'Twilio', class: 'sms' }, + { code: 'mailgun', display: 'Mailgun', class: 'email' }, + { code: 'all-zero-conf', display: 'Always 0-conf', class: 'zeroConf', cryptos: ['BTC', 'ZEC', 'LTC', 'DASH', 'BCH'] }, + { code: 'no-zero-conf', display: 'Always 1-conf', class: 'zeroConf', cryptos: ALL_CRYPTOS }, + { code: 'blockcypher', display: 'Blockcypher', class: 'zeroConf', cryptos: ['BTC'] }, + { code: 'mock-zero-conf', display: 'Mock 0-conf', class: 'zeroConf', cryptos: ['BTC', 'ZEC', 'LTC', 'DASH', 'BCH', 'ETH'] } ], - machines: machineList.map(machine => ({machine: machine.deviceId, display: machine.name})) + machines: machineList.map(machine => ({ machine: machine.deviceId, display: machine.name })) })) .then((data) => { return filterAccounts(data, devMode) diff --git a/lib/blockchain/lightning.js b/lib/blockchain/lightning.js new file mode 100644 index 00000000..e69de29b diff --git a/lib/plugins/wallet/lightning/lightning.js b/lib/plugins/wallet/lightning/lightning.js new file mode 100644 index 00000000..e69de29b From fa0838b30328d4895409d5ee37d97e833a856cb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Thu, 10 Mar 2022 14:39:51 +0000 Subject: [PATCH 02/24] feat: wallet plugin structure --- lib/admin/config.js | 17 ++++--- lib/blockchain/lightning.js | 0 lib/plugins/wallet/lightning/galoy.js | 61 +++++++++++++++++++++++ lib/plugins/wallet/lightning/lightning.js | 0 4 files changed, 70 insertions(+), 8 deletions(-) delete mode 100644 lib/blockchain/lightning.js create mode 100644 lib/plugins/wallet/lightning/galoy.js delete mode 100644 lib/plugins/wallet/lightning/lightning.js diff --git a/lib/admin/config.js b/lib/admin/config.js index ab22df32..b669d0be 100644 --- a/lib/admin/config.js +++ b/lib/admin/config.js @@ -177,11 +177,11 @@ function fetchData () { languages: languages, countries, accounts: [ - { code: 'bitpay', display: 'Bitpay', class: 'ticker', cryptos: ['BTC', 'BCH'] }, - { code: 'kraken', display: 'Kraken', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH'] }, - { code: 'bitstamp', display: 'Bitstamp', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'BCH'] }, - { code: 'coinbase', display: 'Coinbase', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'BCH', 'ZEC', 'DASH'] }, - { code: 'itbit', display: 'itBit', class: 'ticker', cryptos: ['BTC', 'ETH'] }, + { code: 'bitpay', display: 'Bitpay', class: 'ticker', cryptos: ['BTC', 'BCH', 'LN'] }, + { code: 'kraken', display: 'Kraken', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH', 'LN'] }, + { code: 'bitstamp', display: 'Bitstamp', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'BCH', 'LN'] }, + { code: 'coinbase', display: 'Coinbase', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'BCH', 'ZEC', 'DASH', 'LN'] }, + { code: 'itbit', display: 'itBit', class: 'ticker', cryptos: ['BTC', 'ETH', 'LN'] }, { code: 'mock-ticker', display: 'Mock (Caution!)', class: 'ticker', cryptos: ALL_CRYPTOS }, { code: 'bitcoind', display: 'bitcoind', class: 'wallet', cryptos: ['BTC'] }, { code: 'no-layer2', display: 'No Layer 2', class: 'layer2', cryptos: ALL_CRYPTOS }, @@ -192,9 +192,10 @@ function fetchData () { { code: 'dashd', display: 'dashd', class: 'wallet', cryptos: ['DASH'] }, { code: 'bitcoincashd', display: 'bitcoincashd', class: 'wallet', cryptos: ['BCH'] }, { code: 'bitgo', display: 'BitGo', class: 'wallet', cryptos: ['BTC', 'ZEC', 'LTC', 'BCH', 'DASH'] }, - { code: 'bitstamp', display: 'Bitstamp', class: 'exchange', cryptos: ['BTC', 'ETH', 'LTC', 'BCH'] }, - { code: 'itbit', display: 'itBit', class: 'exchange', cryptos: ['BTC', 'ETH'] }, - { code: 'kraken', display: 'Kraken', class: 'exchange', cryptos: ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH'] }, + { code: 'galoy', display: 'Galoy', class: 'wallet', cryptos: ['LN'] }, + { code: 'bitstamp', display: 'Bitstamp', class: 'exchange', cryptos: ['BTC', 'ETH', 'LTC', 'BCH', 'LN'] }, + { code: 'itbit', display: 'itBit', class: 'exchange', cryptos: ['BTC', 'ETH', 'LN'] }, + { code: 'kraken', display: 'Kraken', class: 'exchange', cryptos: ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH', 'LN'] }, { code: 'mock-wallet', display: 'Mock (Caution!)', class: 'wallet', cryptos: ALL_CRYPTOS }, { code: 'no-exchange', display: 'No exchange', class: 'exchange', cryptos: ALL_CRYPTOS }, { code: 'mock-exchange', display: 'Mock exchange', class: 'exchange', cryptos: ALL_CRYPTOS }, diff --git a/lib/blockchain/lightning.js b/lib/blockchain/lightning.js deleted file mode 100644 index e69de29b..00000000 diff --git a/lib/plugins/wallet/lightning/galoy.js b/lib/plugins/wallet/lightning/galoy.js new file mode 100644 index 00000000..459675df --- /dev/null +++ b/lib/plugins/wallet/lightning/galoy.js @@ -0,0 +1,61 @@ +const BN = require('../../../bn') + +const NAME = 'LN' +const SUPPORTED_COINS = ['BTC'] + +function checkCryptoCode (cryptoCode) { + if (!SUPPORTED_COINS.includes(cryptoCode)) { + return Promise.reject(new Error('Unsupported crypto: ' + cryptoCode)) + } + + return Promise.resolve() +} + +function getWallet () { + // Create wallet instance +} + +function sendCoins (account, tx, settings, operatorId) { + // const { toAddress, cryptoAtoms, cryptoCode } = tx + return {} +} + +function balance (account, cryptoCode, settings, operatorId) { + return checkCryptoCode(cryptoCode) + .then(() => getWallet(account, cryptoCode)) + .then(wallet => new BN(wallet._wallet.spendableBalanceString)) +} + +function newAddress (account, info, tx, settings, operatorId) { + return checkCryptoCode(info.cryptoCode) +} + +function getStatus (account, tx, requested, settings, operatorId) { + const { cryptoCode } = tx + return checkCryptoCode(cryptoCode).then(() => {}) +} + +function newFunding (account, cryptoCode, settings, operatorId) { + return checkCryptoCode(cryptoCode) +} + +function cryptoNetwork (account, cryptoCode, settings, operatorId) { + return checkCryptoCode(cryptoCode) + .then(() => account.environment === 'test' ? 'test' : 'main') +} + +function checkBlockchainStatus (cryptoCode) { + return checkCryptoCode(cryptoCode) + .then(() => Promise.resolve('ready')) +} + +module.exports = { + NAME, + balance, + sendCoins, + newAddress, + getStatus, + newFunding, + cryptoNetwork, + checkBlockchainStatus +} diff --git a/lib/plugins/wallet/lightning/lightning.js b/lib/plugins/wallet/lightning/lightning.js deleted file mode 100644 index e69de29b..00000000 From 443e73d6cdb36c731b0ac020701d8b2119595467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Wed, 9 Mar 2022 16:03:11 +0000 Subject: [PATCH 03/24] feat: format config file --- lib/blockchain/lightning.js | 0 lib/plugins/wallet/lightning/lightning.js | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 lib/blockchain/lightning.js create mode 100644 lib/plugins/wallet/lightning/lightning.js diff --git a/lib/blockchain/lightning.js b/lib/blockchain/lightning.js new file mode 100644 index 00000000..e69de29b diff --git a/lib/plugins/wallet/lightning/lightning.js b/lib/plugins/wallet/lightning/lightning.js new file mode 100644 index 00000000..e69de29b From 355434ced3f9b3cc26609eeef8bdce02780fd8c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Thu, 10 Mar 2022 14:39:51 +0000 Subject: [PATCH 04/24] feat: wallet plugin structure --- lib/blockchain/lightning.js | 0 lib/plugins/wallet/lightning/lightning.js | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 lib/blockchain/lightning.js delete mode 100644 lib/plugins/wallet/lightning/lightning.js diff --git a/lib/blockchain/lightning.js b/lib/blockchain/lightning.js deleted file mode 100644 index e69de29b..00000000 diff --git a/lib/plugins/wallet/lightning/lightning.js b/lib/plugins/wallet/lightning/lightning.js deleted file mode 100644 index e69de29b..00000000 From 12a7ed0bd607ca8c5df0254b8f569a7d79345832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Mon, 14 Mar 2022 17:11:56 +0000 Subject: [PATCH 05/24] feat: add galoy config and UI safeguards --- lib/admin/config.js | 2 +- lib/new-admin/config/accounts.js | 3 ++- lib/new-admin/services/funding.js | 2 +- lib/plugins/wallet/{lightning => galoy}/galoy.js | 7 ++----- new-lamassu-admin/src/pages/Blacklist/Blacklist.js | 5 +++-- new-lamassu-admin/src/pages/Wallet/WizardSplash.js | 2 ++ 6 files changed, 11 insertions(+), 10 deletions(-) rename lib/plugins/wallet/{lightning => galoy}/galoy.js (86%) diff --git a/lib/admin/config.js b/lib/admin/config.js index b669d0be..4ad3c96d 100644 --- a/lib/admin/config.js +++ b/lib/admin/config.js @@ -153,7 +153,7 @@ const mapLanguage = lang => { const supportedLanguages = languageRec.supported const languages = supportedLanguages.map(mapLanguage).filter(r => r) -const ALL_CRYPTOS = ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH'] +const ALL_CRYPTOS = ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH', 'LN'] const filterAccounts = (data, isDevMode) => { const notAllowed = ['mock-ticker', 'mock-wallet', 'mock-exchange', 'mock-sms', 'mock-id-verify', 'mock-zero-conf'] diff --git a/lib/new-admin/config/accounts.js b/lib/new-admin/config/accounts.js index 05ab6089..199b96bc 100644 --- a/lib/new-admin/config/accounts.js +++ b/lib/new-admin/config/accounts.js @@ -3,7 +3,7 @@ const _ = require('lodash/fp') const { ALL } = require('../../plugins/common/ccxt') -const { BTC, BCH, DASH, ETH, LTC, USDT, ZEC, XMR, TRX, USDT_TRON } = COINS +const { BTC, BCH, DASH, ETH, LTC, USDT, ZEC, XMR, LN, TRX, USDT_TRON } = COINS const { bitpay, coinbase, itbit, bitstamp, kraken, binanceus, cex, binance } = ALL const TICKER = 'ticker' @@ -37,6 +37,7 @@ const ALL_ACCOUNTS = [ { code: 'monerod', display: 'monerod', class: WALLET, cryptos: [XMR] }, { code: 'bitcoincashd', display: 'bitcoincashd', class: WALLET, cryptos: [BCH] }, { code: 'bitgo', display: 'BitGo', class: WALLET, cryptos: [BTC, ZEC, LTC, BCH, DASH] }, + { code: 'galoy', display: 'Galoy', class: WALLET, cryptos: [LN] }, { code: 'bitstamp', display: 'Bitstamp', class: EXCHANGE, cryptos: bitstamp.CRYPTO }, { code: 'itbit', display: 'itBit', class: EXCHANGE, cryptos: itbit.CRYPTO }, { code: 'kraken', display: 'Kraken', class: EXCHANGE, cryptos: kraken.CRYPTO }, diff --git a/lib/new-admin/services/funding.js b/lib/new-admin/services/funding.js index 5b425d82..8f748696 100644 --- a/lib/new-admin/services/funding.js +++ b/lib/new-admin/services/funding.js @@ -57,7 +57,7 @@ const reflect = p => p.then(value => ({ value, status: 'fulfilled' }), error => function getFunding () { return settingsLoader.loadLatest().then(settings => { - const cryptoCodes = configManager.getAllCryptoCurrencies(settings.config) + const cryptoCodes = _.filter(code => coinUtils.getExternalCryptoCode(code) === code)(configManager.getAllCryptoCurrencies(settings.config)) const fiatCode = configManager.getGlobalLocale(settings.config).fiatCurrency const pareCoins = c => _.includes(c.cryptoCode, cryptoCodes) const cryptoCurrencies = coinUtils.cryptoCurrencies() diff --git a/lib/plugins/wallet/lightning/galoy.js b/lib/plugins/wallet/galoy/galoy.js similarity index 86% rename from lib/plugins/wallet/lightning/galoy.js rename to lib/plugins/wallet/galoy/galoy.js index 459675df..49c849c5 100644 --- a/lib/plugins/wallet/lightning/galoy.js +++ b/lib/plugins/wallet/galoy/galoy.js @@ -1,7 +1,5 @@ -const BN = require('../../../bn') - const NAME = 'LN' -const SUPPORTED_COINS = ['BTC'] +const SUPPORTED_COINS = ['LN'] function checkCryptoCode (cryptoCode) { if (!SUPPORTED_COINS.includes(cryptoCode)) { @@ -23,7 +21,6 @@ function sendCoins (account, tx, settings, operatorId) { function balance (account, cryptoCode, settings, operatorId) { return checkCryptoCode(cryptoCode) .then(() => getWallet(account, cryptoCode)) - .then(wallet => new BN(wallet._wallet.spendableBalanceString)) } function newAddress (account, info, tx, settings, operatorId) { @@ -41,7 +38,7 @@ function newFunding (account, cryptoCode, settings, operatorId) { function cryptoNetwork (account, cryptoCode, settings, operatorId) { return checkCryptoCode(cryptoCode) - .then(() => account.environment === 'test' ? 'test' : 'main') + .then(() => {}) } function checkBlockchainStatus (cryptoCode) { diff --git a/new-lamassu-admin/src/pages/Blacklist/Blacklist.js b/new-lamassu-admin/src/pages/Blacklist/Blacklist.js index e0ac4f42..a7d6e0a9 100644 --- a/new-lamassu-admin/src/pages/Blacklist/Blacklist.js +++ b/new-lamassu-admin/src/pages/Blacklist/Blacklist.js @@ -142,8 +142,9 @@ const Blacklist = () => { const classes = useStyles() const blacklistData = R.path(['blacklist'])(blacklistResponse) ?? [] - const availableCurrencies = - R.path(['cryptoCurrencies'], blacklistResponse) ?? [] + const availableCurrencies = R.filter( + coin => coinUtils.getExternalCryptoCode(coin.code) === coin.code + )(R.path(['cryptoCurrencies'], blacklistResponse) ?? []) const formattedData = groupByCode(blacklistData) diff --git a/new-lamassu-admin/src/pages/Wallet/WizardSplash.js b/new-lamassu-admin/src/pages/Wallet/WizardSplash.js index 48692da2..925cbdf2 100644 --- a/new-lamassu-admin/src/pages/Wallet/WizardSplash.js +++ b/new-lamassu-admin/src/pages/Wallet/WizardSplash.js @@ -60,6 +60,8 @@ const getLogo = code => { return MoneroLogo case 'TRX': return TronLogo + case 'LN': + return BitcoinLogo default: return null } From 49bd2d16e34f3ce02844baedbf0ae84a70847c59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Wed, 23 Mar 2022 23:48:49 +0000 Subject: [PATCH 06/24] feat: galoy wallet plugin --- lib/plugins/wallet/galoy/galoy.js | 253 +++++++++++++++++++++++++++++- 1 file changed, 245 insertions(+), 8 deletions(-) diff --git a/lib/plugins/wallet/galoy/galoy.js b/lib/plugins/wallet/galoy/galoy.js index 49c849c5..0c771602 100644 --- a/lib/plugins/wallet/galoy/galoy.js +++ b/lib/plugins/wallet/galoy/galoy.js @@ -1,5 +1,38 @@ + +const _ = require('lodash/fp') + +const axios = require('axios') const NAME = 'LN' const SUPPORTED_COINS = ['LN'] +const PHONE = '+3500000000000' + +const URI = 'https://api.staging.galoy.io/graphql' + +const BN = require('../../../bn') + +function request (graphqlQuery, token) { + const headers = { + 'content-type': 'application/json', + 'Authorization': token || '' + } + return Promise.resolve(true) + .then(() => { + return axios({ + method: 'post', + url: URI, + headers: headers, + data: graphqlQuery + }) + }) + .then(r => { + console.log(r) + if (r.error) throw r.error + return r.data + }) + .catch(err => { + throw new Error(err) + }) +} function checkCryptoCode (cryptoCode) { if (!SUPPORTED_COINS.includes(cryptoCode)) { @@ -9,36 +42,234 @@ function checkCryptoCode (cryptoCode) { return Promise.resolve() } -function getWallet () { - // Create wallet instance +function getGaloyAccount (token) { + const accountInfo = { + 'operationName': 'me', + 'query': `query me { + me { + createdAt + defaultAccount { + ...AccountFragment + } + id + phone + twoFAEnabled + username + } + }`, + 'variables': {} + } + return request(accountInfo, token) + .then(r => { + return r.data.data.defaultAccount + }) + .catch(err => { + throw new Error(err) + }) +} + +function fetchAuthToken (config) { + const phone = config.phone + // userRequestAuthCode deprecated? + const regularRequestAuthCode = { + 'operationName': 'userRequestAuthCode', + 'query': `mutation userRequestAuthCode($input: UserRequestAuthCodeInput!) { + userRequestAuthCode(input: $input) { + errors { + ...ErrorFragment + } + success + } + }`, + 'variables': { 'input': { 'phone': `${phone}` } } + } + const createCaptcha = { + 'operationName': 'captchaCreateChallenge', + 'query': `mutation captchaCreateChallenge { + captchaCreateChallenge { + errors { + ...ErrorFragment + } + result { + ...CaptchaCreateChallengeResultFragment + } + } + }`, + 'variables': {} + } + const captchaRequestAuthCode = { + 'operationName': 'captchaRequestAuthCode', + 'query': `mutation captchaRequestAuthCode($input: CaptchaRequestAuthCodeInput!) { + captchaRequestAuthCode(input: $input) { + errors { + ...ErrorFragment + } + success + } + }`, + 'variables': {} + } + + return request(regularRequestAuthCode) + .then(r => { + console.log(r) + return r + }) +} + +function isLightning (address) { + return address.substr(0, 2) === 'ln' } function sendCoins (account, tx, settings, operatorId) { - // const { toAddress, cryptoAtoms, cryptoCode } = tx - return {} + const { toAddress, cryptoAtoms, cryptoCode } = tx + // Is walletId a mandatory field? + const sendOnChain = { + 'operationName': 'onChainPaymentSend', + 'query': `mutation onChainPaymentSend($input: OnChainPaymentSendInput!) { + onChainPaymentSend(input: $input) { + errors { + ...ErrorFragment + } + status + } + }`, + 'variables': { 'input': { 'address': `${toAddress}`, 'amount': `${cryptoAtoms}` } } + } + const sendLN = { + 'operationName': 'lnInvoicePaymentSend', + 'query': `mutation lnInvoicePaymentSend($input: LnInvoicePaymentInput!) { + lnInvoicePaymentSend(input: $input) { + errors { + ...ErrorFragment + } + status + } + }`, + 'variables': { 'input': { 'paymentRequest': `${toAddress}` } } + } + return checkCryptoCode(cryptoCode) + .then(() => fetchAuthToken({ phone: PHONE })) + .then(authToken => { + if (isLightning) { + return request(sendLN, authToken) + } + return request(sendOnChain, authToken) + }) + .then(result => { + return result.data + }) + .catch(err => { + throw err + }) +} + +function newOnChainAddress (walletId, token) { + const createOnChainAddress = { + 'operationName': 'onChainAddressCreate', + 'query': `mutation onChainAddressCreate($input: OnChainAddressCreateInput!) { + onChainAddressCreate(input: $input) { + address + errors { + ...ErrorFragment + } + } + }`, + 'variables': { 'input': { 'walletId': `${walletId}` } } + } + return request(createOnChainAddress, token) + .then(result => { + return result.data.onChainAddressCreate.address + }) + .catch(err => { + throw err + }) +} + +function newInvoice (walletId, cryptoAtoms, token) { + const createInvoice = { + 'operationName': 'lnInvoiceCreate', + 'query': `mutation lnInvoiceCreate($input: LnInvoiceCreateInput!) { + lnInvoiceCreate(input: $input) { + errors { + ...ErrorFragment + } + invoice { + ...LnInvoiceFragment + } + } + }`, + 'variables': { 'input': { 'walletId': `${walletId}`, 'amount': `${cryptoAtoms}` } } + } + return request(createInvoice, token) + .then(result => { + return result.data.lnInvoiceCreate.invoice.paymentRequest + }) + .catch(err => { + throw err + }) } function balance (account, cryptoCode, settings, operatorId) { return checkCryptoCode(cryptoCode) - .then(() => getWallet(account, cryptoCode)) + .then(() => fetchAuthToken({ phone: PHONE })) + .then(authToken => getGaloyAccount(authToken)) + .then(account => { + // account has a list of wallets, should we consider the balance of each one? + // for now we'll pick the first BTC wallet that matches the defaultWalletId + const wallet = _.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === account.defaultWalletId)(account.wallets) + return new BN(wallet.balance || 0) + }) + .catch(err => { + throw err + }) } function newAddress (account, info, tx, settings, operatorId) { + const { cryptoAtoms, cryptoCode } = tx return checkCryptoCode(info.cryptoCode) + .then(() => fetchAuthToken({ phone: PHONE })) + .then(authToken => [getGaloyAccount(authToken), authToken]) + .then(([account, authToken]) => { + const wallet = _.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === account.defaultWalletId)(account.wallets) + const promises = [ + newOnChainAddress(wallet.id, authToken), + newInvoice(wallet.id, cryptoAtoms, authToken) + ] + return Promise.all(promises) + }) + .then(([onChainAddress, invoice]) => { + return `bitcoin:${onChainAddress}?amount=${cryptoAtoms}?lightning=${invoice}` + }) } function getStatus (account, tx, requested, settings, operatorId) { - const { cryptoCode } = tx - return checkCryptoCode(cryptoCode).then(() => {}) + // Type Transaction has a field status + // but we're not sure if it's interchangeable with our status definition } function newFunding (account, cryptoCode, settings, operatorId) { + // Has to be a regular BTC address return checkCryptoCode(cryptoCode) + .then(() => fetchAuthToken({ phone: PHONE })) + .then(authToken => [getGaloyAccount(authToken), authToken]) + .then(([account, authToken]) => { + const wallet = _.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === account.defaultWalletId)(account.wallets) + return newOnChainAddress(wallet.id, authToken) + .then(onChainAddress => [onChainAddress, wallet.balance]) + }) + .then(([onChainAddress, balance]) => { + // Missing pending balance + return { + fundingConfirmedBalance: new BN(balance), + fundingAddress: onChainAddress + } + }) } function cryptoNetwork (account, cryptoCode, settings, operatorId) { return checkCryptoCode(cryptoCode) - .then(() => {}) + .then(() => account.environment === 'test' ? 'test' : 'main') } function checkBlockchainStatus (cryptoCode) { @@ -46,6 +277,12 @@ function checkBlockchainStatus (cryptoCode) { .then(() => Promise.resolve('ready')) } +sendCoins({}, { + toAddress: 'lnbc10n1p3z7tpkpp5fjkptx4xtnh5n5vyrrhrw25f86mv0rwyu9a8tm3lrwnkl4u58zqdqg23jhxap3cqzpgxqyz5vqsp5g239kch2r7q9dty8rgs2h94h0d6tp8ssws9zte9qzvss2fr729zs9qyyssq86khhqz86dhftteqd0ymad32dfrdfdmdac8jw359wn4s0fx5gfyrectl4e49pt38gculfk3xeljv5ygd8ddry0m0z38lqt23j8aytycqrd4med', + cryptoCode: 'LN', + cryptoAtoms: 123123 +}, {}, {}) + module.exports = { NAME, balance, From dd55cda986dd68a290a687e635d7dfff0d58ce2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Tue, 5 Apr 2022 17:54:11 +0100 Subject: [PATCH 07/24] feat: retrieve account info --- lib/plugins/wallet/galoy/galoy.js | 175 ++++++++++++++++++++++-------- 1 file changed, 132 insertions(+), 43 deletions(-) diff --git a/lib/plugins/wallet/galoy/galoy.js b/lib/plugins/wallet/galoy/galoy.js index 0c771602..a9540c37 100644 --- a/lib/plugins/wallet/galoy/galoy.js +++ b/lib/plugins/wallet/galoy/galoy.js @@ -3,8 +3,9 @@ const _ = require('lodash/fp') const axios = require('axios') const NAME = 'LN' -const SUPPORTED_COINS = ['LN'] +const SUPPORTED_COINS = ['LN', 'BTC'] const PHONE = '+3500000000000' +const TEST_AUTH_TOKEN = '' const URI = 'https://api.staging.galoy.io/graphql' @@ -13,7 +14,7 @@ const BN = require('../../../bn') function request (graphqlQuery, token) { const headers = { 'content-type': 'application/json', - 'Authorization': token || '' + 'Authorization': `Bearer ${token || TEST_AUTH_TOKEN}` } return Promise.resolve(true) .then(() => { @@ -25,7 +26,6 @@ function request (graphqlQuery, token) { }) }) .then(r => { - console.log(r) if (r.error) throw r.error return r.data }) @@ -49,7 +49,48 @@ function getGaloyAccount (token) { me { createdAt defaultAccount { - ...AccountFragment + defaultWalletId + wallets { + id + walletCurrency + balance + transactions { + edges { + node { + createdAt + direction + id + settlementAmount + settlementFee + status + initiationVia { + ... on InitiationViaIntraLedger { + counterPartyUsername + counterPartyWalletId + } + ... on InitiationViaLn { + paymentHash + } + ... on InitiationViaOnChain { + address + } + } + settlementVia { + ... on SettlementViaIntraLedger { + counterPartyUsername + counterPartyWalletId + } + ... on SettlementViaLn { + preImage + } + ... on SettlementViaOnChain { + transactionHash + } + } + } + } + } + } } id phone @@ -61,7 +102,7 @@ function getGaloyAccount (token) { } return request(accountInfo, token) .then(r => { - return r.data.data.defaultAccount + return r.data.me.defaultAccount }) .catch(err => { throw new Error(err) @@ -76,7 +117,8 @@ function fetchAuthToken (config) { 'query': `mutation userRequestAuthCode($input: UserRequestAuthCodeInput!) { userRequestAuthCode(input: $input) { errors { - ...ErrorFragment + message + path } success } @@ -88,32 +130,41 @@ function fetchAuthToken (config) { 'query': `mutation captchaCreateChallenge { captchaCreateChallenge { errors { - ...ErrorFragment + message + path } result { - ...CaptchaCreateChallengeResultFragment + challengeCode + id } } }`, 'variables': {} } - const captchaRequestAuthCode = { + const captchaRequestAuthCode = code => ({ 'operationName': 'captchaRequestAuthCode', 'query': `mutation captchaRequestAuthCode($input: CaptchaRequestAuthCodeInput!) { captchaRequestAuthCode(input: $input) { errors { - ...ErrorFragment + message + path } success } }`, - 'variables': {} - } + 'variables': { 'input': { 'phone': `${phone}`, 'challengeCode': `${code.challengeCode}`, 'secCode': `${code.challengeCode.slice(0, 5)}`, 'validationCode': `${code.challengeCode.slice(0, 5)}` } } + }) - return request(regularRequestAuthCode) + return request(createCaptcha) .then(r => { - console.log(r) - return r + const code = r.data.captchaCreateChallenge.result + if (code) { + // captchaRequestAuthCode parameters have to be processed by geetest + return request(captchaRequestAuthCode(code)) + } + }) + .catch(err => { + throw new Error(err) }) } @@ -121,43 +172,66 @@ function isLightning (address) { return address.substr(0, 2) === 'ln' } -function sendCoins (account, tx, settings, operatorId) { - const { toAddress, cryptoAtoms, cryptoCode } = tx - // Is walletId a mandatory field? +function sendFundsOnChain (walletId, address, cryptoAtoms, token) { const sendOnChain = { 'operationName': 'onChainPaymentSend', 'query': `mutation onChainPaymentSend($input: OnChainPaymentSendInput!) { onChainPaymentSend(input: $input) { errors { - ...ErrorFragment + message + path } status } }`, - 'variables': { 'input': { 'address': `${toAddress}`, 'amount': `${cryptoAtoms}` } } + 'variables': { 'input': { 'address': `${address}`, 'amount': `${cryptoAtoms}`, 'walletId': `${walletId}` } } } + return request(sendOnChain, token) + .then(result => { + return result.data.onChainPaymentSend + }) + .catch(err => { + throw err + }) +} + +function sendFundsLN (walletId, invoice, token) { const sendLN = { 'operationName': 'lnInvoicePaymentSend', 'query': `mutation lnInvoicePaymentSend($input: LnInvoicePaymentInput!) { lnInvoicePaymentSend(input: $input) { errors { - ...ErrorFragment + message + path } status } }`, - 'variables': { 'input': { 'paymentRequest': `${toAddress}` } } + 'variables': { 'input': { 'paymentRequest': `${invoice}`, 'walletId': `${walletId}` } } } + return request(sendLN, token) + .then(result => { + return result.data.onChainPaymentSend + }) + .catch(err => { + throw err + }) +} + +function sendCoins (account, tx, settings, operatorId) { + const { toAddress, cryptoAtoms, cryptoCode } = tx return checkCryptoCode(cryptoCode) - .then(() => fetchAuthToken({ phone: PHONE })) - .then(authToken => { - if (isLightning) { - return request(sendLN, authToken) + // .then(() => fetchAuthToken({ phone: PHONE })) + .then(authToken => Promise.all([getGaloyAccount(authToken), authToken])) + .then(([account, authToken]) => { + const wallet = _.head(_.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === account.defaultWalletId)(account.wallets)) + if (isLightning(toAddress)) { + return sendFundsLN(wallet.id, toAddress, authToken) } - return request(sendOnChain, authToken) + return sendFundsOnChain(wallet.id, toAddress, cryptoAtoms, authToken) }) .then(result => { - return result.data + return result }) .catch(err => { throw err @@ -171,7 +245,8 @@ function newOnChainAddress (walletId, token) { onChainAddressCreate(input: $input) { address errors { - ...ErrorFragment + message + path } } }`, @@ -192,10 +267,11 @@ function newInvoice (walletId, cryptoAtoms, token) { 'query': `mutation lnInvoiceCreate($input: LnInvoiceCreateInput!) { lnInvoiceCreate(input: $input) { errors { - ...ErrorFragment + message + path } invoice { - ...LnInvoiceFragment + paymentRequest } } }`, @@ -212,12 +288,14 @@ function newInvoice (walletId, cryptoAtoms, token) { function balance (account, cryptoCode, settings, operatorId) { return checkCryptoCode(cryptoCode) - .then(() => fetchAuthToken({ phone: PHONE })) + // .then(() => fetchAuthToken({ phone: PHONE })) .then(authToken => getGaloyAccount(authToken)) .then(account => { + console.log(account) // account has a list of wallets, should we consider the balance of each one? // for now we'll pick the first BTC wallet that matches the defaultWalletId - const wallet = _.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === account.defaultWalletId)(account.wallets) + const wallet = _.head(_.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === account.defaultWalletId)(account.wallets)) + console.log(wallet) return new BN(wallet.balance || 0) }) .catch(err => { @@ -227,11 +305,11 @@ function balance (account, cryptoCode, settings, operatorId) { function newAddress (account, info, tx, settings, operatorId) { const { cryptoAtoms, cryptoCode } = tx - return checkCryptoCode(info.cryptoCode) - .then(() => fetchAuthToken({ phone: PHONE })) - .then(authToken => [getGaloyAccount(authToken), authToken]) + return checkCryptoCode(cryptoCode) + // .then(() => fetchAuthToken({ phone: PHONE })) + .then(authToken => Promise.all([getGaloyAccount(authToken), authToken])) .then(([account, authToken]) => { - const wallet = _.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === account.defaultWalletId)(account.wallets) + const wallet = _.head(_.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === account.defaultWalletId)(account.wallets)) const promises = [ newOnChainAddress(wallet.id, authToken), newInvoice(wallet.id, cryptoAtoms, authToken) @@ -251,7 +329,7 @@ function getStatus (account, tx, requested, settings, operatorId) { function newFunding (account, cryptoCode, settings, operatorId) { // Has to be a regular BTC address return checkCryptoCode(cryptoCode) - .then(() => fetchAuthToken({ phone: PHONE })) + // .then(() => fetchAuthToken({ phone: PHONE })) .then(authToken => [getGaloyAccount(authToken), authToken]) .then(([account, authToken]) => { const wallet = _.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === account.defaultWalletId)(account.wallets) @@ -277,11 +355,22 @@ function checkBlockchainStatus (cryptoCode) { .then(() => Promise.resolve('ready')) } -sendCoins({}, { - toAddress: 'lnbc10n1p3z7tpkpp5fjkptx4xtnh5n5vyrrhrw25f86mv0rwyu9a8tm3lrwnkl4u58zqdqg23jhxap3cqzpgxqyz5vqsp5g239kch2r7q9dty8rgs2h94h0d6tp8ssws9zte9qzvss2fr729zs9qyyssq86khhqz86dhftteqd0ymad32dfrdfdmdac8jw359wn4s0fx5gfyrectl4e49pt38gculfk3xeljv5ygd8ddry0m0z38lqt23j8aytycqrd4med', - cryptoCode: 'LN', - cryptoAtoms: 123123 -}, {}, {}) +// sendCoins({}, { +// toAddress: 'tb1ql7w62elx9ucw4pj5lgw4l028hmuw80sndtntxt', +// cryptoCode: 'BTC', +// cryptoAtoms: 1000 +// }, {}, {}) +// .then(r => console.log(r)) + +// balance({}, 'BTC', {}, {}) +// .then(r => console.log()) +// getGaloyAccount() +// newAddress({}, {}, { cryptoCode: 'BTC', cryptoAtoms: 1 }, {}) +// .then(r => console.log(r)) + +// Test faucet addresses +// tb1qfyt7cgds7z8ssthtnhh35s608059yzk0hwgcqd 1) +// tb1qmflph389nz5ev05jypzvcglyguyrl2qhyaag6r 2) module.exports = { NAME, From 09cb924106405a7bc5d7a65b6c581372f3762b01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Thu, 7 Apr 2022 13:37:36 +0100 Subject: [PATCH 08/24] feat: calculate pending balance --- lib/plugins/wallet/galoy/galoy.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/plugins/wallet/galoy/galoy.js b/lib/plugins/wallet/galoy/galoy.js index a9540c37..932dbf9c 100644 --- a/lib/plugins/wallet/galoy/galoy.js +++ b/lib/plugins/wallet/galoy/galoy.js @@ -4,8 +4,7 @@ const _ = require('lodash/fp') const axios = require('axios') const NAME = 'LN' const SUPPORTED_COINS = ['LN', 'BTC'] -const PHONE = '+3500000000000' -const TEST_AUTH_TOKEN = '' +const TX_PENDING = 'PENDING' const URI = 'https://api.staging.galoy.io/graphql' @@ -211,7 +210,7 @@ function sendFundsLN (walletId, invoice, token) { } return request(sendLN, token) .then(result => { - return result.data.onChainPaymentSend + return result.data.lnInvoicePaymentSend }) .catch(err => { throw err @@ -330,15 +329,19 @@ function newFunding (account, cryptoCode, settings, operatorId) { // Has to be a regular BTC address return checkCryptoCode(cryptoCode) // .then(() => fetchAuthToken({ phone: PHONE })) - .then(authToken => [getGaloyAccount(authToken), authToken]) + .then(authToken => Promise.all([getGaloyAccount(authToken), authToken])) .then(([account, authToken]) => { - const wallet = _.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === account.defaultWalletId)(account.wallets) + const wallet = _.head(_.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === account.defaultWalletId)(account.wallets)) + const pendingBalance = _.sumBy(tx => { + if (tx.node.status === TX_PENDING) return tx.node.settlementAmount + return 0 + })(wallet.transactions.edges) return newOnChainAddress(wallet.id, authToken) - .then(onChainAddress => [onChainAddress, wallet.balance]) + .then(onChainAddress => [onChainAddress, wallet.balance, pendingBalance]) }) - .then(([onChainAddress, balance]) => { - // Missing pending balance + .then(([onChainAddress, balance, pendingBalance]) => { return { + fundingPendingBalance: new BN(pendingBalance), fundingConfirmedBalance: new BN(balance), fundingAddress: onChainAddress } From f37a73f9839e297b094acf45a80809af2e733c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Thu, 7 Apr 2022 21:33:38 +0100 Subject: [PATCH 09/24] feat: fetch cash-out transaction status --- lib/plugins/wallet/galoy/galoy.js | 202 ++++++++------- package-lock.json | 398 ++++++++++++++++++++++++------ package.json | 1 + 3 files changed, 426 insertions(+), 175 deletions(-) diff --git a/lib/plugins/wallet/galoy/galoy.js b/lib/plugins/wallet/galoy/galoy.js index 932dbf9c..1147cc85 100644 --- a/lib/plugins/wallet/galoy/galoy.js +++ b/lib/plugins/wallet/galoy/galoy.js @@ -1,10 +1,11 @@ const _ = require('lodash/fp') - +const invoice = require('@node-lightning/invoice') const axios = require('axios') const NAME = 'LN' const SUPPORTED_COINS = ['LN', 'BTC'] const TX_PENDING = 'PENDING' +const TX_SUCCESS = 'SUCCESS' const URI = 'https://api.staging.galoy.io/graphql' @@ -13,7 +14,7 @@ const BN = require('../../../bn') function request (graphqlQuery, token) { const headers = { 'content-type': 'application/json', - 'Authorization': `Bearer ${token || TEST_AUTH_TOKEN}` + 'Authorization': `Bearer ${token}` } return Promise.resolve(true) .then(() => { @@ -108,65 +109,6 @@ function getGaloyAccount (token) { }) } -function fetchAuthToken (config) { - const phone = config.phone - // userRequestAuthCode deprecated? - const regularRequestAuthCode = { - 'operationName': 'userRequestAuthCode', - 'query': `mutation userRequestAuthCode($input: UserRequestAuthCodeInput!) { - userRequestAuthCode(input: $input) { - errors { - message - path - } - success - } - }`, - 'variables': { 'input': { 'phone': `${phone}` } } - } - const createCaptcha = { - 'operationName': 'captchaCreateChallenge', - 'query': `mutation captchaCreateChallenge { - captchaCreateChallenge { - errors { - message - path - } - result { - challengeCode - id - } - } - }`, - 'variables': {} - } - const captchaRequestAuthCode = code => ({ - 'operationName': 'captchaRequestAuthCode', - 'query': `mutation captchaRequestAuthCode($input: CaptchaRequestAuthCodeInput!) { - captchaRequestAuthCode(input: $input) { - errors { - message - path - } - success - } - }`, - 'variables': { 'input': { 'phone': `${phone}`, 'challengeCode': `${code.challengeCode}`, 'secCode': `${code.challengeCode.slice(0, 5)}`, 'validationCode': `${code.challengeCode.slice(0, 5)}` } } - }) - - return request(createCaptcha) - .then(r => { - const code = r.data.captchaCreateChallenge.result - if (code) { - // captchaRequestAuthCode parameters have to be processed by geetest - return request(captchaRequestAuthCode(code)) - } - }) - .catch(err => { - throw new Error(err) - }) -} - function isLightning (address) { return address.substr(0, 2) === 'ln' } @@ -220,14 +162,13 @@ function sendFundsLN (walletId, invoice, token) { function sendCoins (account, tx, settings, operatorId) { const { toAddress, cryptoAtoms, cryptoCode } = tx return checkCryptoCode(cryptoCode) - // .then(() => fetchAuthToken({ phone: PHONE })) - .then(authToken => Promise.all([getGaloyAccount(authToken), authToken])) - .then(([account, authToken]) => { - const wallet = _.head(_.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === account.defaultWalletId)(account.wallets)) + .then(() => getGaloyAccount(account.authToken)) + .then(galoyAccount => { + const wallet = _.head(_.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === galoyAccount.defaultWalletId)(galoyAccount.wallets)) if (isLightning(toAddress)) { - return sendFundsLN(wallet.id, toAddress, authToken) + return sendFundsLN(wallet.id, toAddress, account.authToken) } - return sendFundsOnChain(wallet.id, toAddress, cryptoAtoms, authToken) + return sendFundsOnChain(wallet.id, toAddress, cryptoAtoms, account.authToken) }) .then(result => { return result @@ -287,13 +228,11 @@ function newInvoice (walletId, cryptoAtoms, token) { function balance (account, cryptoCode, settings, operatorId) { return checkCryptoCode(cryptoCode) - // .then(() => fetchAuthToken({ phone: PHONE })) - .then(authToken => getGaloyAccount(authToken)) - .then(account => { - console.log(account) + .then(() => getGaloyAccount(account.authToken)) + .then(galoyAccount => { // account has a list of wallets, should we consider the balance of each one? - // for now we'll pick the first BTC wallet that matches the defaultWalletId - const wallet = _.head(_.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === account.defaultWalletId)(account.wallets)) + // for now we'll get the first BTC wallet that matches the defaultWalletId + const wallet = _.head(_.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === galoyAccount.defaultWalletId)(galoyAccount.wallets)) console.log(wallet) return new BN(wallet.balance || 0) }) @@ -305,13 +244,12 @@ function balance (account, cryptoCode, settings, operatorId) { function newAddress (account, info, tx, settings, operatorId) { const { cryptoAtoms, cryptoCode } = tx return checkCryptoCode(cryptoCode) - // .then(() => fetchAuthToken({ phone: PHONE })) - .then(authToken => Promise.all([getGaloyAccount(authToken), authToken])) - .then(([account, authToken]) => { - const wallet = _.head(_.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === account.defaultWalletId)(account.wallets)) + .then(() => getGaloyAccount(account.authToken)) + .then(galoyAccount => { + const wallet = _.head(_.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === galoyAccount.defaultWalletId)(galoyAccount.wallets)) const promises = [ - newOnChainAddress(wallet.id, authToken), - newInvoice(wallet.id, cryptoAtoms, authToken) + newOnChainAddress(wallet.id, account.authToken), + newInvoice(wallet.id, cryptoAtoms, account.authToken) ] return Promise.all(promises) }) @@ -321,22 +259,39 @@ function newAddress (account, info, tx, settings, operatorId) { } function getStatus (account, tx, requested, settings, operatorId) { - // Type Transaction has a field status - // but we're not sure if it's interchangeable with our status definition + const { toAddress, cryptoAtoms, cryptoCode } = tx + const mapStatus = status => { + if (status === TX_PENDING) return 'authorized' + if (status === TX_SUCCESS) return 'confirmed' + return 'notSeen' + } + return checkCryptoCode(cryptoCode) + .then(() => getGaloyAccount(account.authToken)) + .then(galoyAccount => { + const wallet = _.head(_.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === galoyAccount.defaultWalletId)(galoyAccount.wallets)) + const transactions = wallet.transactions.edges + if (isLightning(toAddress)) { + const paymentHash = invoice.decode(toAddress).paymentHash.toString('hex') + const transaction = _.head(_.filter(tx => tx.node.initiationVia.paymentHash === paymentHash && tx.node.direction === 'RECEIVE')(transactions)) + return { receivedCryptoAtoms: cryptoAtoms, status: mapStatus(transaction.node.status) } + } + // On-chain tx + const transaction = _.head(_.filter(tx => tx.node.initiationVia.address === toAddress)(transactions)) + return { receivedCryptoAtoms: cryptoAtoms, status: mapStatus(transaction.node.status) } + }) } function newFunding (account, cryptoCode, settings, operatorId) { - // Has to be a regular BTC address + // Regular BTC address return checkCryptoCode(cryptoCode) - // .then(() => fetchAuthToken({ phone: PHONE })) - .then(authToken => Promise.all([getGaloyAccount(authToken), authToken])) - .then(([account, authToken]) => { - const wallet = _.head(_.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === account.defaultWalletId)(account.wallets)) + .then(() => getGaloyAccount(account.authToken)) + .then(galoyAccount => { + const wallet = _.head(_.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === galoyAccount.defaultWalletId)(galoyAccount.wallets)) const pendingBalance = _.sumBy(tx => { if (tx.node.status === TX_PENDING) return tx.node.settlementAmount return 0 })(wallet.transactions.edges) - return newOnChainAddress(wallet.id, authToken) + return newOnChainAddress(wallet.id, account.authToken) .then(onChainAddress => [onChainAddress, wallet.balance, pendingBalance]) }) .then(([onChainAddress, balance, pendingBalance]) => { @@ -358,22 +313,63 @@ function checkBlockchainStatus (cryptoCode) { .then(() => Promise.resolve('ready')) } -// sendCoins({}, { -// toAddress: 'tb1ql7w62elx9ucw4pj5lgw4l028hmuw80sndtntxt', -// cryptoCode: 'BTC', -// cryptoAtoms: 1000 -// }, {}, {}) -// .then(r => console.log(r)) - -// balance({}, 'BTC', {}, {}) -// .then(r => console.log()) -// getGaloyAccount() -// newAddress({}, {}, { cryptoCode: 'BTC', cryptoAtoms: 1 }, {}) -// .then(r => console.log(r)) - -// Test faucet addresses -// tb1qfyt7cgds7z8ssthtnhh35s608059yzk0hwgcqd 1) -// tb1qmflph389nz5ev05jypzvcglyguyrl2qhyaag6r 2) +// function fetchAuthToken (config) { +// const phone = config.phone +// // userRequestAuthCode deprecated? +// const regularRequestAuthCode = { +// 'operationName': 'userRequestAuthCode', +// 'query': `mutation userRequestAuthCode($input: UserRequestAuthCodeInput!) { +// userRequestAuthCode(input: $input) { +// errors { +// message +// path +// } +// success +// } +// }`, +// 'variables': { 'input': { 'phone': `${phone}` } } +// } +// const createCaptcha = { +// 'operationName': 'captchaCreateChallenge', +// 'query': `mutation captchaCreateChallenge { +// captchaCreateChallenge { +// errors { +// message +// path +// } +// result { +// challengeCode +// id +// } +// } +// }`, +// 'variables': {} +// } +// const captchaRequestAuthCode = code => ({ +// 'operationName': 'captchaRequestAuthCode', +// 'query': `mutation captchaRequestAuthCode($input: CaptchaRequestAuthCodeInput!) { +// captchaRequestAuthCode(input: $input) { +// errors { +// message +// path +// } +// success +// } +// }`, +// 'variables': { 'input': { 'phone': `${phone}`, 'challengeCode': `${code.challengeCode}`, 'secCode': `${code.challengeCode.slice(0, 5)}`, 'validationCode': `${code.challengeCode.slice(0, 5)}` } } +// }) +// return request(createCaptcha) +// .then(r => { +// const code = r.data.captchaCreateChallenge.result +// if (code) { +// // captchaRequestAuthCode parameters have to be processed by geetest +// return request(captchaRequestAuthCode(code)) +// } +// }) +// .catch(err => { +// throw new Error(err) +// }) +// } module.exports = { NAME, diff --git a/package-lock.json b/package-lock.json index 1d663059..78149a1c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -662,6 +662,13 @@ "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", "wif": "^2.0.1" + }, + "dependencies": { + "fastpriorityqueue": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fastpriorityqueue/-/fastpriorityqueue-0.7.4.tgz", + "integrity": "sha512-u7o5oa9R7CMOHo2i8P2/T2nRg5bg/0dDegDSJVzkVkMf/A318LNnujNLfpxlJeXUdDAefrVPqsDV624vUyxNfA==" + } } }, "ecpair": { @@ -685,6 +692,11 @@ "@types/node": "*" } }, + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, "bignumber.js": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-8.1.1.tgz", @@ -717,7 +729,6 @@ "bip174": "npm:@bitgo-forks/bip174@3.0.0-rc.1", "bs58check": "^2.1.2", "create-hash": "^1.1.0", - "fastpriorityqueue": "^0.7.1", "json5": "^2.2.3", "ripemd160": "^2.0.2", "typeforce": "^1.11.3", @@ -945,6 +956,13 @@ "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", "wif": "^2.0.1" + }, + "dependencies": { + "fastpriorityqueue": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fastpriorityqueue/-/fastpriorityqueue-0.7.4.tgz", + "integrity": "sha512-u7o5oa9R7CMOHo2i8P2/T2nRg5bg/0dDegDSJVzkVkMf/A318LNnujNLfpxlJeXUdDAefrVPqsDV624vUyxNfA==" + } } }, "ecpair": { @@ -1026,6 +1044,11 @@ "follow-redirects": "^1.14.7" } }, + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, "bip174": { "version": "npm:bip174@3.0.0-rc.1", "resolved": "https://registry.npmjs.org/@bitgo-forks/bip174/-/bip174-3.0.0-rc.1.tgz", @@ -1053,7 +1076,6 @@ "bip174": "npm:@bitgo-forks/bip174@3.0.0-rc.1", "bs58check": "^2.1.2", "create-hash": "^1.1.0", - "fastpriorityqueue": "^0.7.1", "json5": "^2.2.3", "ripemd160": "^2.0.2", "typeforce": "^1.11.3", @@ -1319,6 +1341,13 @@ "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", "wif": "^2.0.1" + }, + "dependencies": { + "fastpriorityqueue": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fastpriorityqueue/-/fastpriorityqueue-0.7.4.tgz", + "integrity": "sha512-u7o5oa9R7CMOHo2i8P2/T2nRg5bg/0dDegDSJVzkVkMf/A318LNnujNLfpxlJeXUdDAefrVPqsDV624vUyxNfA==" + } } }, "ecpair": { @@ -1342,6 +1371,11 @@ "@types/node": "*" } }, + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, "bignumber.js": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-8.1.1.tgz", @@ -1374,7 +1408,6 @@ "bip174": "npm:@bitgo-forks/bip174@3.0.0-rc.1", "bs58check": "^2.1.2", "create-hash": "^1.1.0", - "fastpriorityqueue": "^0.7.1", "json5": "^2.2.3", "ripemd160": "^2.0.2", "typeforce": "^1.11.3", @@ -1520,6 +1553,13 @@ "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", "wif": "^2.0.1" + }, + "dependencies": { + "fastpriorityqueue": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fastpriorityqueue/-/fastpriorityqueue-0.7.4.tgz", + "integrity": "sha512-u7o5oa9R7CMOHo2i8P2/T2nRg5bg/0dDegDSJVzkVkMf/A318LNnujNLfpxlJeXUdDAefrVPqsDV624vUyxNfA==" + } } }, "ecpair": { @@ -1543,6 +1583,11 @@ "@types/node": "*" } }, + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, "bip174": { "version": "npm:bip174@3.0.0-rc.1", "resolved": "https://registry.npmjs.org/@bitgo-forks/bip174/-/bip174-3.0.0-rc.1.tgz", @@ -1570,7 +1615,6 @@ "bip174": "npm:@bitgo-forks/bip174@3.0.0-rc.1", "bs58check": "^2.1.2", "create-hash": "^1.1.0", - "fastpriorityqueue": "^0.7.1", "json5": "^2.2.3", "ripemd160": "^2.0.2", "typeforce": "^1.11.3", @@ -1783,6 +1827,13 @@ "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", "wif": "^2.0.1" + }, + "dependencies": { + "fastpriorityqueue": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fastpriorityqueue/-/fastpriorityqueue-0.7.4.tgz", + "integrity": "sha512-u7o5oa9R7CMOHo2i8P2/T2nRg5bg/0dDegDSJVzkVkMf/A318LNnujNLfpxlJeXUdDAefrVPqsDV624vUyxNfA==" + } } }, "ecpair": { @@ -1806,6 +1857,11 @@ "@types/node": "*" } }, + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, "bip174": { "version": "npm:bip174@3.0.0-rc.1", "resolved": "https://registry.npmjs.org/@bitgo-forks/bip174/-/bip174-3.0.0-rc.1.tgz", @@ -1833,7 +1889,6 @@ "bip174": "npm:@bitgo-forks/bip174@3.0.0-rc.1", "bs58check": "^2.1.2", "create-hash": "^1.1.0", - "fastpriorityqueue": "^0.7.1", "json5": "^2.2.3", "ripemd160": "^2.0.2", "typeforce": "^1.11.3", @@ -1988,6 +2043,13 @@ "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", "wif": "^2.0.1" + }, + "dependencies": { + "fastpriorityqueue": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fastpriorityqueue/-/fastpriorityqueue-0.7.4.tgz", + "integrity": "sha512-u7o5oa9R7CMOHo2i8P2/T2nRg5bg/0dDegDSJVzkVkMf/A318LNnujNLfpxlJeXUdDAefrVPqsDV624vUyxNfA==" + } } }, "ecpair": { @@ -2011,6 +2073,11 @@ "@types/node": "*" } }, + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, "bip174": { "version": "npm:bip174@3.0.0-rc.1", "resolved": "https://registry.npmjs.org/@bitgo-forks/bip174/-/bip174-3.0.0-rc.1.tgz", @@ -2038,7 +2105,6 @@ "bip174": "npm:@bitgo-forks/bip174@3.0.0-rc.1", "bs58check": "^2.1.2", "create-hash": "^1.1.0", - "fastpriorityqueue": "^0.7.1", "json5": "^2.2.3", "ripemd160": "^2.0.2", "typeforce": "^1.11.3", @@ -2207,6 +2273,13 @@ "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", "wif": "^2.0.1" + }, + "dependencies": { + "fastpriorityqueue": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fastpriorityqueue/-/fastpriorityqueue-0.7.4.tgz", + "integrity": "sha512-u7o5oa9R7CMOHo2i8P2/T2nRg5bg/0dDegDSJVzkVkMf/A318LNnujNLfpxlJeXUdDAefrVPqsDV624vUyxNfA==" + } } }, "ecpair": { @@ -2230,8 +2303,13 @@ "@types/node": "*" } }, + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, "bip174": { - "version": "npm:bip174@3.0.0", + "version": "npm:@bitgo/bip174@3.0.0", "resolved": "https://registry.npmjs.org/@bitgo/bip174/-/bip174-3.0.0.tgz", "integrity": "sha512-Qv98vy6l1WgZwrxKx7IPYY91/+Z3tpALVSDn+Ic9qCsxygCq9gYw5eL8q3kd7LYTFLy/HgcqhcMOa83Spbp4JA==" }, @@ -2249,7 +2327,7 @@ } }, "bitcoinjs-lib": { - "version": "npm:bitcoinjs-lib@7.0.0-rc.3", + "version": "npm:@bitgo/bitcoinjs-lib@7.0.0-rc.3", "resolved": "https://registry.npmjs.org/@bitgo/bitcoinjs-lib/-/bitcoinjs-lib-7.0.0-rc.3.tgz", "integrity": "sha512-IjlaIAuVehVF8azp28n2Gk+xKZ/MdH4t8qOvH2flTSDuYDLcZNHGHXmwyHbOfZwfP5R1MKVrGd+dscm1jqhTkQ==", "requires": { @@ -2257,7 +2335,6 @@ "bip174": "npm:@bitgo/bip174@3.0.0", "bs58check": "^2.1.2", "create-hash": "^1.1.0", - "fastpriorityqueue": "^0.7.1", "ripemd160": "^2.0.2", "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", @@ -2273,7 +2350,7 @@ } }, "ecpair": { - "version": "npm:ecpair@2.1.0-rc.0", + "version": "npm:@bitgo/ecpair@2.1.0-rc.0", "resolved": "https://registry.npmjs.org/@bitgo/ecpair/-/ecpair-2.1.0-rc.0.tgz", "integrity": "sha512-qPZetcEA1Lzzm9NsqsGF9NGorAGaXrv20eZjopLUjsdwftWcsYTE7lwzE/Xjdf4fcq6G4+vjrCudWAMGNfJqOQ==", "requires": { @@ -2443,6 +2520,13 @@ "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", "wif": "^2.0.1" + }, + "dependencies": { + "fastpriorityqueue": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fastpriorityqueue/-/fastpriorityqueue-0.7.4.tgz", + "integrity": "sha512-u7o5oa9R7CMOHo2i8P2/T2nRg5bg/0dDegDSJVzkVkMf/A318LNnujNLfpxlJeXUdDAefrVPqsDV624vUyxNfA==" + } } }, "ecpair": { @@ -2466,6 +2550,11 @@ "@types/node": "*" } }, + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, "bip174": { "version": "npm:bip174@3.0.0-rc.1", "resolved": "https://registry.npmjs.org/@bitgo-forks/bip174/-/bip174-3.0.0-rc.1.tgz", @@ -2493,7 +2582,6 @@ "bip174": "npm:@bitgo-forks/bip174@3.0.0-rc.1", "bs58check": "^2.1.2", "create-hash": "^1.1.0", - "fastpriorityqueue": "^0.7.1", "json5": "^2.2.3", "ripemd160": "^2.0.2", "typeforce": "^1.11.3", @@ -2666,6 +2754,13 @@ "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", "wif": "^2.0.1" + }, + "dependencies": { + "fastpriorityqueue": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fastpriorityqueue/-/fastpriorityqueue-0.7.4.tgz", + "integrity": "sha512-u7o5oa9R7CMOHo2i8P2/T2nRg5bg/0dDegDSJVzkVkMf/A318LNnujNLfpxlJeXUdDAefrVPqsDV624vUyxNfA==" + } } }, "ecpair": { @@ -2689,8 +2784,13 @@ "@types/node": "*" } }, + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, "bip174": { - "version": "npm:bip174@3.0.0-rc.1", + "version": "npm:@bitgo-forks/bip174@3.0.0-rc.1", "resolved": "https://registry.npmjs.org/@bitgo-forks/bip174/-/bip174-3.0.0-rc.1.tgz", "integrity": "sha512-eGi5die7Q7O3yPtkcGF1gD7qLlJLiLnYI4DpFTF6tUhUo71gy3RoXAAeeJA2fLpnVoJofXnLdLfpcO6OEZAsvw==" }, @@ -2716,7 +2816,6 @@ "bip174": "npm:@bitgo-forks/bip174@3.0.0-rc.1", "bs58check": "^2.1.2", "create-hash": "^1.1.0", - "fastpriorityqueue": "^0.7.1", "json5": "^2.2.3", "ripemd160": "^2.0.2", "typeforce": "^1.11.3", @@ -2733,7 +2832,7 @@ } }, "ecpair": { - "version": "npm:ecpair@2.1.0-rc.0", + "version": "npm:@bitgo/ecpair@2.1.0-rc.0", "resolved": "https://registry.npmjs.org/@bitgo/ecpair/-/ecpair-2.1.0-rc.0.tgz", "integrity": "sha512-qPZetcEA1Lzzm9NsqsGF9NGorAGaXrv20eZjopLUjsdwftWcsYTE7lwzE/Xjdf4fcq6G4+vjrCudWAMGNfJqOQ==", "requires": { @@ -2874,6 +2973,13 @@ "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", "wif": "^2.0.1" + }, + "dependencies": { + "fastpriorityqueue": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fastpriorityqueue/-/fastpriorityqueue-0.7.4.tgz", + "integrity": "sha512-u7o5oa9R7CMOHo2i8P2/T2nRg5bg/0dDegDSJVzkVkMf/A318LNnujNLfpxlJeXUdDAefrVPqsDV624vUyxNfA==" + } } }, "ecpair": { @@ -2897,6 +3003,11 @@ "@types/node": "*" } }, + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, "bignumber.js": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-8.1.1.tgz", @@ -2929,7 +3040,6 @@ "bip174": "npm:@bitgo-forks/bip174@3.0.0-rc.1", "bs58check": "^2.1.2", "create-hash": "^1.1.0", - "fastpriorityqueue": "^0.7.1", "json5": "^2.2.3", "ripemd160": "^2.0.2", "typeforce": "^1.11.3", @@ -3087,6 +3197,13 @@ "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", "wif": "^2.0.1" + }, + "dependencies": { + "fastpriorityqueue": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fastpriorityqueue/-/fastpriorityqueue-0.7.4.tgz", + "integrity": "sha512-u7o5oa9R7CMOHo2i8P2/T2nRg5bg/0dDegDSJVzkVkMf/A318LNnujNLfpxlJeXUdDAefrVPqsDV624vUyxNfA==" + } } }, "ecpair": { @@ -3118,6 +3235,11 @@ "follow-redirects": "^1.14.7" } }, + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, "bip174": { "version": "npm:bip174@3.0.0-rc.1", "resolved": "https://registry.npmjs.org/@bitgo-forks/bip174/-/bip174-3.0.0-rc.1.tgz", @@ -3145,7 +3267,6 @@ "bip174": "npm:@bitgo-forks/bip174@3.0.0-rc.1", "bs58check": "^2.1.2", "create-hash": "^1.1.0", - "fastpriorityqueue": "^0.7.1", "json5": "^2.2.3", "ripemd160": "^2.0.2", "typeforce": "^1.11.3", @@ -3337,6 +3458,13 @@ "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", "wif": "^2.0.1" + }, + "dependencies": { + "fastpriorityqueue": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fastpriorityqueue/-/fastpriorityqueue-0.7.4.tgz", + "integrity": "sha512-u7o5oa9R7CMOHo2i8P2/T2nRg5bg/0dDegDSJVzkVkMf/A318LNnujNLfpxlJeXUdDAefrVPqsDV624vUyxNfA==" + } } }, "ecpair": { @@ -3360,6 +3488,11 @@ "@types/node": "*" } }, + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, "bip174": { "version": "npm:bip174@3.0.0-rc.1", "resolved": "https://registry.npmjs.org/@bitgo-forks/bip174/-/bip174-3.0.0-rc.1.tgz", @@ -3387,7 +3520,6 @@ "bip174": "npm:@bitgo-forks/bip174@3.0.0-rc.1", "bs58check": "^2.1.2", "create-hash": "^1.1.0", - "fastpriorityqueue": "^0.7.1", "json5": "^2.2.3", "ripemd160": "^2.0.2", "typeforce": "^1.11.3", @@ -3580,6 +3712,13 @@ "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", "wif": "^2.0.1" + }, + "dependencies": { + "fastpriorityqueue": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fastpriorityqueue/-/fastpriorityqueue-0.7.4.tgz", + "integrity": "sha512-u7o5oa9R7CMOHo2i8P2/T2nRg5bg/0dDegDSJVzkVkMf/A318LNnujNLfpxlJeXUdDAefrVPqsDV624vUyxNfA==" + } } }, "ecpair": { @@ -3603,6 +3742,11 @@ "@types/node": "*" } }, + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, "bip174": { "version": "npm:bip174@3.0.0-rc.1", "resolved": "https://registry.npmjs.org/@bitgo-forks/bip174/-/bip174-3.0.0-rc.1.tgz", @@ -3630,7 +3774,6 @@ "bip174": "npm:@bitgo-forks/bip174@3.0.0-rc.1", "bs58check": "^2.1.2", "create-hash": "^1.1.0", - "fastpriorityqueue": "^0.7.1", "json5": "^2.2.3", "ripemd160": "^2.0.2", "typeforce": "^1.11.3", @@ -3818,6 +3961,13 @@ "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", "wif": "^2.0.1" + }, + "dependencies": { + "fastpriorityqueue": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fastpriorityqueue/-/fastpriorityqueue-0.7.4.tgz", + "integrity": "sha512-u7o5oa9R7CMOHo2i8P2/T2nRg5bg/0dDegDSJVzkVkMf/A318LNnujNLfpxlJeXUdDAefrVPqsDV624vUyxNfA==" + } } }, "ecpair": { @@ -3841,6 +3991,11 @@ "@types/node": "*" } }, + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, "bip174": { "version": "npm:bip174@3.0.0-rc.1", "resolved": "https://registry.npmjs.org/@bitgo-forks/bip174/-/bip174-3.0.0-rc.1.tgz", @@ -3868,7 +4023,6 @@ "bip174": "npm:@bitgo-forks/bip174@3.0.0-rc.1", "bs58check": "^2.1.2", "create-hash": "^1.1.0", - "fastpriorityqueue": "^0.7.1", "json5": "^2.2.3", "ripemd160": "^2.0.2", "typeforce": "^1.11.3", @@ -4023,6 +4177,13 @@ "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", "wif": "^2.0.1" + }, + "dependencies": { + "fastpriorityqueue": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fastpriorityqueue/-/fastpriorityqueue-0.7.4.tgz", + "integrity": "sha512-u7o5oa9R7CMOHo2i8P2/T2nRg5bg/0dDegDSJVzkVkMf/A318LNnujNLfpxlJeXUdDAefrVPqsDV624vUyxNfA==" + } } }, "ecpair": { @@ -4046,6 +4207,11 @@ "@types/node": "*" } }, + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, "bip174": { "version": "npm:bip174@3.0.0-rc.1", "resolved": "https://registry.npmjs.org/@bitgo-forks/bip174/-/bip174-3.0.0-rc.1.tgz", @@ -4073,7 +4239,6 @@ "bip174": "npm:@bitgo-forks/bip174@3.0.0-rc.1", "bs58check": "^2.1.2", "create-hash": "^1.1.0", - "fastpriorityqueue": "^0.7.1", "json5": "^2.2.3", "ripemd160": "^2.0.2", "typeforce": "^1.11.3", @@ -4229,6 +4394,13 @@ "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", "wif": "^2.0.1" + }, + "dependencies": { + "fastpriorityqueue": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fastpriorityqueue/-/fastpriorityqueue-0.7.4.tgz", + "integrity": "sha512-u7o5oa9R7CMOHo2i8P2/T2nRg5bg/0dDegDSJVzkVkMf/A318LNnujNLfpxlJeXUdDAefrVPqsDV624vUyxNfA==" + } } }, "ecpair": { @@ -4252,8 +4424,13 @@ "@types/node": "*" } }, + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, "bip174": { - "version": "npm:bip174@3.0.0-rc.1", + "version": "npm:bip174@npm:bip174@3.0.0-rc.1", "resolved": "https://registry.npmjs.org/@bitgo-forks/bip174/-/bip174-3.0.0-rc.1.tgz", "integrity": "sha512-eGi5die7Q7O3yPtkcGF1gD7qLlJLiLnYI4DpFTF6tUhUo71gy3RoXAAeeJA2fLpnVoJofXnLdLfpcO6OEZAsvw==" }, @@ -4276,10 +4453,8 @@ "integrity": "sha512-D62U1pWej8M+7gROykLGGPvFf0zFal10kAAbuaHuy1ohtwKLNHRiUz8dpdjEZBzNkF+pU+GQhItdiEJTslK4/A==", "requires": { "bech32": "^2.0.0", - "bip174": "npm:@bitgo-forks/bip174@3.0.0-rc.1", "bs58check": "^2.1.2", "create-hash": "^1.1.0", - "fastpriorityqueue": "^0.7.1", "json5": "^2.2.3", "ripemd160": "^2.0.2", "typeforce": "^1.11.3", @@ -4296,7 +4471,7 @@ } }, "ecpair": { - "version": "npm:ecpair@2.1.0-rc.0", + "version": "npm:ecpair@npm:ecpair@2.1.0-rc.0", "resolved": "https://registry.npmjs.org/@bitgo/ecpair/-/ecpair-2.1.0-rc.0.tgz", "integrity": "sha512-qPZetcEA1Lzzm9NsqsGF9NGorAGaXrv20eZjopLUjsdwftWcsYTE7lwzE/Xjdf4fcq6G4+vjrCudWAMGNfJqOQ==", "requires": { @@ -4433,6 +4608,13 @@ "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", "wif": "^2.0.1" + }, + "dependencies": { + "fastpriorityqueue": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fastpriorityqueue/-/fastpriorityqueue-0.7.4.tgz", + "integrity": "sha512-u7o5oa9R7CMOHo2i8P2/T2nRg5bg/0dDegDSJVzkVkMf/A318LNnujNLfpxlJeXUdDAefrVPqsDV624vUyxNfA==" + } } }, "ecpair": { @@ -4456,8 +4638,13 @@ "@types/node": "*" } }, + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, "bip174": { - "version": "npm:bip174@3.0.0-rc.1", + "version": "npm:@bitgo-forks/bip174@3.0.0-rc.1", "resolved": "https://registry.npmjs.org/@bitgo-forks/bip174/-/bip174-3.0.0-rc.1.tgz", "integrity": "sha512-eGi5die7Q7O3yPtkcGF1gD7qLlJLiLnYI4DpFTF6tUhUo71gy3RoXAAeeJA2fLpnVoJofXnLdLfpcO6OEZAsvw==" }, @@ -4483,7 +4670,6 @@ "bip174": "npm:@bitgo-forks/bip174@3.0.0-rc.1", "bs58check": "^2.1.2", "create-hash": "^1.1.0", - "fastpriorityqueue": "^0.7.1", "json5": "^2.2.3", "ripemd160": "^2.0.2", "typeforce": "^1.11.3", @@ -4500,7 +4686,7 @@ } }, "ecpair": { - "version": "npm:ecpair@2.1.0-rc.0", + "version": "npm:@bitgo/ecpair@2.1.0-rc.0", "resolved": "https://registry.npmjs.org/@bitgo/ecpair/-/ecpair-2.1.0-rc.0.tgz", "integrity": "sha512-qPZetcEA1Lzzm9NsqsGF9NGorAGaXrv20eZjopLUjsdwftWcsYTE7lwzE/Xjdf4fcq6G4+vjrCudWAMGNfJqOQ==", "requires": { @@ -4640,6 +4826,13 @@ "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", "wif": "^2.0.1" + }, + "dependencies": { + "fastpriorityqueue": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fastpriorityqueue/-/fastpriorityqueue-0.7.4.tgz", + "integrity": "sha512-u7o5oa9R7CMOHo2i8P2/T2nRg5bg/0dDegDSJVzkVkMf/A318LNnujNLfpxlJeXUdDAefrVPqsDV624vUyxNfA==" + } } }, "ecpair": { @@ -5041,6 +5234,11 @@ "@types/node": "*" } }, + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, "bip174": { "version": "npm:bip174@3.0.0-rc.1", "resolved": "https://registry.npmjs.org/@bitgo-forks/bip174/-/bip174-3.0.0-rc.1.tgz", @@ -5068,7 +5266,6 @@ "bip174": "npm:@bitgo-forks/bip174@3.0.0-rc.1", "bs58check": "^2.1.2", "create-hash": "^1.1.0", - "fastpriorityqueue": "^0.7.1", "json5": "^2.2.3", "ripemd160": "^2.0.2", "typeforce": "^1.11.3", @@ -5267,6 +5464,13 @@ "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", "wif": "^2.0.1" + }, + "dependencies": { + "fastpriorityqueue": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fastpriorityqueue/-/fastpriorityqueue-0.7.4.tgz", + "integrity": "sha512-u7o5oa9R7CMOHo2i8P2/T2nRg5bg/0dDegDSJVzkVkMf/A318LNnujNLfpxlJeXUdDAefrVPqsDV624vUyxNfA==" + } } }, "ecpair": { @@ -5290,6 +5494,11 @@ "@types/node": "*" } }, + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, "bip174": { "version": "npm:bip174@3.0.0-rc.1", "resolved": "https://registry.npmjs.org/@bitgo-forks/bip174/-/bip174-3.0.0-rc.1.tgz", @@ -5317,7 +5526,6 @@ "bip174": "npm:@bitgo-forks/bip174@3.0.0-rc.1", "bs58check": "^2.1.2", "create-hash": "^1.1.0", - "fastpriorityqueue": "^0.7.1", "json5": "^2.2.3", "ripemd160": "^2.0.2", "typeforce": "^1.11.3", @@ -5454,6 +5662,13 @@ "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", "wif": "^2.0.1" + }, + "dependencies": { + "fastpriorityqueue": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fastpriorityqueue/-/fastpriorityqueue-0.7.4.tgz", + "integrity": "sha512-u7o5oa9R7CMOHo2i8P2/T2nRg5bg/0dDegDSJVzkVkMf/A318LNnujNLfpxlJeXUdDAefrVPqsDV624vUyxNfA==" + } } }, "ecpair": { @@ -5477,6 +5692,11 @@ "@types/node": "*" } }, + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, "bip174": { "version": "npm:bip174@3.0.0", "resolved": "https://registry.npmjs.org/@bitgo/bip174/-/bip174-3.0.0.tgz", @@ -5504,7 +5724,6 @@ "bip174": "npm:@bitgo/bip174@3.0.0", "bs58check": "^2.1.2", "create-hash": "^1.1.0", - "fastpriorityqueue": "^0.7.1", "ripemd160": "^2.0.2", "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", @@ -6885,6 +7104,13 @@ "ethereumjs-icap": "^0.3.1", "keccak256": "^1.0.2", "lodash": "^4.17.10" + }, + "dependencies": { + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + } } }, "@mapbox/node-pre-gyp": { @@ -6994,6 +7220,30 @@ "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.6.3.tgz", "integrity": "sha512-T04e4iTurVy7I8Sw4+c5OSN9/RkPlo1uKxAomtxQNLq8j1uPAqnsqG1bqvY3Jv7c13gyr6dui0zmh/I3+f/JaQ==" }, + "@node-lightning/bufio": { + "version": "0.22.1", + "resolved": "https://registry.npmjs.org/@node-lightning/bufio/-/bufio-0.22.1.tgz", + "integrity": "sha512-RsVS8J20qGva2QFZTnFFH93g/fOQ+qBm9APtRQI2VP+oWSICIarWrery83m1GKTzZ1IjpWbiiC9PHwdk6DkSsg==" + }, + "@node-lightning/crypto": { + "version": "0.22.1", + "resolved": "https://registry.npmjs.org/@node-lightning/crypto/-/crypto-0.22.1.tgz", + "integrity": "sha512-uNnhc2/6auOvzTdZ68OrhEMzq/ePc+nNe6f+F2TU4gTFLZYlYvsdKl7UBcmzhxMnWdHxVupVmIHuvgi29r6xGA==", + "requires": { + "secp256k1": "^4.0.2" + } + }, + "@node-lightning/invoice": { + "version": "0.22.1", + "resolved": "https://registry.npmjs.org/@node-lightning/invoice/-/invoice-0.22.1.tgz", + "integrity": "sha512-bXwZhMhAvuqHqW5ptNEThfnmmcmYuRB6r2wKrtK1FgMafzNN6RwLHHCZuYP+V3cudoJ4Ythsl1c84wq+XRAD0A==", + "requires": { + "@node-lightning/bufio": "^0.22.1", + "@node-lightning/crypto": "^0.22.1", + "bech32": "^1.1.3", + "bs58check": "^2.1.2" + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -8553,39 +8803,24 @@ "dev": true }, "@vonage/auth": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vonage/auth/-/auth-1.5.0.tgz", - "integrity": "sha512-h2xEFKYW9IyEfFzf1OVzIVZj3/81qlY9S2LThPVFnkkbcXBe4Uph2So4giCF2to8sZ4WJNmFW63cd4S/i1qdgg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vonage/auth/-/auth-1.6.0.tgz", + "integrity": "sha512-Tde2p9HDAcYEzKfMRA1RLHChcqU8zCc2eAvpfx5WHjQSZRLQK3B5BZHjbHP7EnBYDtdX+tjwuLQD641dWElReQ==", "requires": { - "@vonage/jwt": "^1.5.0", + "@vonage/jwt": "^1.6.0", "debug": "^4.3.4" }, "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "@vonage/jwt": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vonage/jwt/-/jwt-1.6.0.tgz", + "integrity": "sha512-AYZCHW0kebs36sNyw5LCZH2HujSpJe8+dpd35fQriyq4qlaMtXoR5xeIaiK6AWIxsCrgEWFVHFyO8resIE3zsA==", "requires": { - "ms": "2.1.2" + "debug": "^4.3.4", + "jsonwebtoken": "^9.0.0", + "uuid": "^9.0.0" } }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "@vonage/jwt": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vonage/jwt/-/jwt-1.5.0.tgz", - "integrity": "sha512-H2RCqrxkODC0qssT3l4/HpaKiZSuurqjD37WS1ohcuUJVBiVAIOIG5t6N0CobY1M/Oqe9RrNSOeIyMuSh+87+A==", - "requires": { - "debug": "^4.3.4", - "jsonwebtoken": "^9.0.0", - "uuid": "^9.0.0" - }, - "dependencies": { "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -8595,14 +8830,20 @@ } }, "jsonwebtoken": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz", - "integrity": "sha512-K8wx7eJ5TPvEjuiVSkv167EVboBDv9PZdDoF7BgeQnBLVvZWW9clr2PsQHVJDTKaEIH5JBIwHujGcHp7GgI2eg==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", "requires": { "jws": "^3.2.2", - "lodash": "^4.17.21", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", "ms": "^2.1.1", - "semver": "^7.3.8" + "semver": "^7.5.4" } }, "ms": { @@ -8610,10 +8851,18 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "requires": { + "lru-cache": "^6.0.0" + } + }, "uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==" } } }, @@ -10116,6 +10365,11 @@ "form-data": "^4.0.0" } }, + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, "bip39": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.4.tgz", @@ -10523,9 +10777,9 @@ } }, "bech32": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", - "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" }, "big-integer": { "version": "1.6.51", @@ -10726,6 +10980,11 @@ "lodash": "^4.17.20" }, "dependencies": { + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, "bn.js": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", @@ -14990,11 +15249,6 @@ "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz", "integrity": "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==" }, - "fastpriorityqueue": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/fastpriorityqueue/-/fastpriorityqueue-0.7.4.tgz", - "integrity": "sha512-u7o5oa9R7CMOHo2i8P2/T2nRg5bg/0dDegDSJVzkVkMf/A318LNnujNLfpxlJeXUdDAefrVPqsDV624vUyxNfA==" - }, "fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", diff --git a/package.json b/package.json index f1386dc1..051eba5e 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "@ethereumjs/tx": "^3.5.1", "@graphql-tools/merge": "^6.2.5", "@lamassu/coins": "v1.3.3", + "@node-lightning/invoice": "0.22.1", "@simplewebauthn/server": "^3.0.0", "@vonage/auth": "^1.5.0", "@vonage/sms": "^1.7.0", From 46f6879108fc3a3064d246b8ca6b9e183e006e26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Thu, 7 Apr 2022 21:48:24 +0100 Subject: [PATCH 10/24] feat: sendCoins error handling --- lib/plugins/wallet/galoy/galoy.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/plugins/wallet/galoy/galoy.js b/lib/plugins/wallet/galoy/galoy.js index 1147cc85..a3c1c39c 100644 --- a/lib/plugins/wallet/galoy/galoy.js +++ b/lib/plugins/wallet/galoy/galoy.js @@ -171,7 +171,14 @@ function sendCoins (account, tx, settings, operatorId) { return sendFundsOnChain(wallet.id, toAddress, cryptoAtoms, account.authToken) }) .then(result => { - return result + switch (result.status) { + case 'ALREADY_PAID': + throw new Error('Transaction already exists!') + case 'FAILURE': + throw new Error('Transaction failed!') + default: + return '' + } }) .catch(err => { throw err From 06e6b2f6579e1150fb979ca0cff5f8f4557c9179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Wed, 9 Mar 2022 16:03:11 +0000 Subject: [PATCH 11/24] feat: format config file --- lib/blockchain/lightning.js | 0 lib/plugins/wallet/lightning/lightning.js | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 lib/blockchain/lightning.js create mode 100644 lib/plugins/wallet/lightning/lightning.js diff --git a/lib/blockchain/lightning.js b/lib/blockchain/lightning.js new file mode 100644 index 00000000..e69de29b diff --git a/lib/plugins/wallet/lightning/lightning.js b/lib/plugins/wallet/lightning/lightning.js new file mode 100644 index 00000000..e69de29b From 12ef86ebbfba06a0b165f322c0b7cf0e6d98ec0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Thu, 10 Mar 2022 14:39:51 +0000 Subject: [PATCH 12/24] feat: wallet plugin structure --- lib/blockchain/lightning.js | 0 lib/plugins/wallet/lightning/galoy.js | 61 +++++++++++++++++++++++ lib/plugins/wallet/lightning/lightning.js | 0 3 files changed, 61 insertions(+) delete mode 100644 lib/blockchain/lightning.js create mode 100644 lib/plugins/wallet/lightning/galoy.js delete mode 100644 lib/plugins/wallet/lightning/lightning.js diff --git a/lib/blockchain/lightning.js b/lib/blockchain/lightning.js deleted file mode 100644 index e69de29b..00000000 diff --git a/lib/plugins/wallet/lightning/galoy.js b/lib/plugins/wallet/lightning/galoy.js new file mode 100644 index 00000000..459675df --- /dev/null +++ b/lib/plugins/wallet/lightning/galoy.js @@ -0,0 +1,61 @@ +const BN = require('../../../bn') + +const NAME = 'LN' +const SUPPORTED_COINS = ['BTC'] + +function checkCryptoCode (cryptoCode) { + if (!SUPPORTED_COINS.includes(cryptoCode)) { + return Promise.reject(new Error('Unsupported crypto: ' + cryptoCode)) + } + + return Promise.resolve() +} + +function getWallet () { + // Create wallet instance +} + +function sendCoins (account, tx, settings, operatorId) { + // const { toAddress, cryptoAtoms, cryptoCode } = tx + return {} +} + +function balance (account, cryptoCode, settings, operatorId) { + return checkCryptoCode(cryptoCode) + .then(() => getWallet(account, cryptoCode)) + .then(wallet => new BN(wallet._wallet.spendableBalanceString)) +} + +function newAddress (account, info, tx, settings, operatorId) { + return checkCryptoCode(info.cryptoCode) +} + +function getStatus (account, tx, requested, settings, operatorId) { + const { cryptoCode } = tx + return checkCryptoCode(cryptoCode).then(() => {}) +} + +function newFunding (account, cryptoCode, settings, operatorId) { + return checkCryptoCode(cryptoCode) +} + +function cryptoNetwork (account, cryptoCode, settings, operatorId) { + return checkCryptoCode(cryptoCode) + .then(() => account.environment === 'test' ? 'test' : 'main') +} + +function checkBlockchainStatus (cryptoCode) { + return checkCryptoCode(cryptoCode) + .then(() => Promise.resolve('ready')) +} + +module.exports = { + NAME, + balance, + sendCoins, + newAddress, + getStatus, + newFunding, + cryptoNetwork, + checkBlockchainStatus +} diff --git a/lib/plugins/wallet/lightning/lightning.js b/lib/plugins/wallet/lightning/lightning.js deleted file mode 100644 index e69de29b..00000000 From f870b9f563db02378300c9c454c587758b50c356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Mon, 14 Mar 2022 17:11:56 +0000 Subject: [PATCH 13/24] feat: add galoy config and UI safeguards --- lib/plugins/wallet/galoy/galoy.js | 84 --------------------------- lib/plugins/wallet/lightning/galoy.js | 61 ------------------- 2 files changed, 145 deletions(-) delete mode 100644 lib/plugins/wallet/lightning/galoy.js diff --git a/lib/plugins/wallet/galoy/galoy.js b/lib/plugins/wallet/galoy/galoy.js index a3c1c39c..433a2ea2 100644 --- a/lib/plugins/wallet/galoy/galoy.js +++ b/lib/plugins/wallet/galoy/galoy.js @@ -1,4 +1,3 @@ - const _ = require('lodash/fp') const invoice = require('@node-lightning/invoice') const axios = require('axios') @@ -29,9 +28,6 @@ function request (graphqlQuery, token) { if (r.error) throw r.error return r.data }) - .catch(err => { - throw new Error(err) - }) } function checkCryptoCode (cryptoCode) { @@ -104,9 +100,6 @@ function getGaloyAccount (token) { .then(r => { return r.data.me.defaultAccount }) - .catch(err => { - throw new Error(err) - }) } function isLightning (address) { @@ -131,9 +124,6 @@ function sendFundsOnChain (walletId, address, cryptoAtoms, token) { .then(result => { return result.data.onChainPaymentSend }) - .catch(err => { - throw err - }) } function sendFundsLN (walletId, invoice, token) { @@ -154,9 +144,6 @@ function sendFundsLN (walletId, invoice, token) { .then(result => { return result.data.lnInvoicePaymentSend }) - .catch(err => { - throw err - }) } function sendCoins (account, tx, settings, operatorId) { @@ -180,9 +167,6 @@ function sendCoins (account, tx, settings, operatorId) { return '' } }) - .catch(err => { - throw err - }) } function newOnChainAddress (walletId, token) { @@ -203,9 +187,6 @@ function newOnChainAddress (walletId, token) { .then(result => { return result.data.onChainAddressCreate.address }) - .catch(err => { - throw err - }) } function newInvoice (walletId, cryptoAtoms, token) { @@ -228,9 +209,6 @@ function newInvoice (walletId, cryptoAtoms, token) { .then(result => { return result.data.lnInvoiceCreate.invoice.paymentRequest }) - .catch(err => { - throw err - }) } function balance (account, cryptoCode, settings, operatorId) { @@ -240,12 +218,8 @@ function balance (account, cryptoCode, settings, operatorId) { // account has a list of wallets, should we consider the balance of each one? // for now we'll get the first BTC wallet that matches the defaultWalletId const wallet = _.head(_.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === galoyAccount.defaultWalletId)(galoyAccount.wallets)) - console.log(wallet) return new BN(wallet.balance || 0) }) - .catch(err => { - throw err - }) } function newAddress (account, info, tx, settings, operatorId) { @@ -320,64 +294,6 @@ function checkBlockchainStatus (cryptoCode) { .then(() => Promise.resolve('ready')) } -// function fetchAuthToken (config) { -// const phone = config.phone -// // userRequestAuthCode deprecated? -// const regularRequestAuthCode = { -// 'operationName': 'userRequestAuthCode', -// 'query': `mutation userRequestAuthCode($input: UserRequestAuthCodeInput!) { -// userRequestAuthCode(input: $input) { -// errors { -// message -// path -// } -// success -// } -// }`, -// 'variables': { 'input': { 'phone': `${phone}` } } -// } -// const createCaptcha = { -// 'operationName': 'captchaCreateChallenge', -// 'query': `mutation captchaCreateChallenge { -// captchaCreateChallenge { -// errors { -// message -// path -// } -// result { -// challengeCode -// id -// } -// } -// }`, -// 'variables': {} -// } -// const captchaRequestAuthCode = code => ({ -// 'operationName': 'captchaRequestAuthCode', -// 'query': `mutation captchaRequestAuthCode($input: CaptchaRequestAuthCodeInput!) { -// captchaRequestAuthCode(input: $input) { -// errors { -// message -// path -// } -// success -// } -// }`, -// 'variables': { 'input': { 'phone': `${phone}`, 'challengeCode': `${code.challengeCode}`, 'secCode': `${code.challengeCode.slice(0, 5)}`, 'validationCode': `${code.challengeCode.slice(0, 5)}` } } -// }) -// return request(createCaptcha) -// .then(r => { -// const code = r.data.captchaCreateChallenge.result -// if (code) { -// // captchaRequestAuthCode parameters have to be processed by geetest -// return request(captchaRequestAuthCode(code)) -// } -// }) -// .catch(err => { -// throw new Error(err) -// }) -// } - module.exports = { NAME, balance, diff --git a/lib/plugins/wallet/lightning/galoy.js b/lib/plugins/wallet/lightning/galoy.js deleted file mode 100644 index 459675df..00000000 --- a/lib/plugins/wallet/lightning/galoy.js +++ /dev/null @@ -1,61 +0,0 @@ -const BN = require('../../../bn') - -const NAME = 'LN' -const SUPPORTED_COINS = ['BTC'] - -function checkCryptoCode (cryptoCode) { - if (!SUPPORTED_COINS.includes(cryptoCode)) { - return Promise.reject(new Error('Unsupported crypto: ' + cryptoCode)) - } - - return Promise.resolve() -} - -function getWallet () { - // Create wallet instance -} - -function sendCoins (account, tx, settings, operatorId) { - // const { toAddress, cryptoAtoms, cryptoCode } = tx - return {} -} - -function balance (account, cryptoCode, settings, operatorId) { - return checkCryptoCode(cryptoCode) - .then(() => getWallet(account, cryptoCode)) - .then(wallet => new BN(wallet._wallet.spendableBalanceString)) -} - -function newAddress (account, info, tx, settings, operatorId) { - return checkCryptoCode(info.cryptoCode) -} - -function getStatus (account, tx, requested, settings, operatorId) { - const { cryptoCode } = tx - return checkCryptoCode(cryptoCode).then(() => {}) -} - -function newFunding (account, cryptoCode, settings, operatorId) { - return checkCryptoCode(cryptoCode) -} - -function cryptoNetwork (account, cryptoCode, settings, operatorId) { - return checkCryptoCode(cryptoCode) - .then(() => account.environment === 'test' ? 'test' : 'main') -} - -function checkBlockchainStatus (cryptoCode) { - return checkCryptoCode(cryptoCode) - .then(() => Promise.resolve('ready')) -} - -module.exports = { - NAME, - balance, - sendCoins, - newAddress, - getStatus, - newFunding, - cryptoNetwork, - checkBlockchainStatus -} From 688ec0bcbc28cf7969e96959b5cc02b928f7e18a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Tue, 12 Apr 2022 17:27:38 +0100 Subject: [PATCH 14/24] feat: galoy account setup --- lib/admin/schemas/gajoy.json | 23 ++++++++++++ lib/new-settings-loader.js | 3 +- lib/plugins/common/ccxt.js | 8 +++-- .../src/pages/Services/schemas/galoy.js | 36 +++++++++++++++++++ .../src/pages/Services/schemas/index.js | 2 ++ .../components/Wallet/ChooseExchange.js | 3 +- .../Wizard/components/Wallet/ChooseTicker.js | 3 +- .../Wizard/components/Wallet/ChooseWallet.js | 16 ++++++++- 8 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 lib/admin/schemas/gajoy.json create mode 100644 new-lamassu-admin/src/pages/Services/schemas/galoy.js diff --git a/lib/admin/schemas/gajoy.json b/lib/admin/schemas/gajoy.json new file mode 100644 index 00000000..5076cc8a --- /dev/null +++ b/lib/admin/schemas/gajoy.json @@ -0,0 +1,23 @@ +{ + "code": "galoy", + "display": "Galoy", + "fields": [ + { + "code": "apiKey", + "display": "API Key", + "fieldType": "string", + "secret": true, + "required": true, + "value": "" + }, + { + "code": "walletId", + "display": "Wallet ID", + "fieldType": "password", + "secret": true, + "required": true, + "value": "" + } + ] + } + \ No newline at end of file diff --git a/lib/new-settings-loader.js b/lib/new-settings-loader.js index 62b9d3fb..1831b9cd 100644 --- a/lib/new-settings-loader.js +++ b/lib/new-settings-loader.js @@ -25,7 +25,8 @@ const SECRET_FIELDS = [ 'binance.privateKey', 'twilio.authToken', 'telnyx.apiKey', - 'vonage.apiSecret' + 'vonage.apiSecret', + 'galoy.walletId' ] /* diff --git a/lib/plugins/common/ccxt.js b/lib/plugins/common/ccxt.js index 6b731d85..c4c54245 100644 --- a/lib/plugins/common/ccxt.js +++ b/lib/plugins/common/ccxt.js @@ -1,5 +1,6 @@ const { COINS } = require('@lamassu/coins') const _ = require('lodash/fp') +const { utils: coinUtils } = require('@lamassu/coins') const kraken = require('../exchange/kraken') const bitstamp = require('../exchange/bitstamp') @@ -27,15 +28,16 @@ const ALL = { } function buildMarket (fiatCode, cryptoCode, serviceName) { - if (!_.includes(cryptoCode, ALL[serviceName].CRYPTO)) { - throw new Error('Unsupported crypto: ' + cryptoCode) + const externalCryptoCode = coinUtils.getExternalCryptoCode(cryptoCode) + if (!_.includes(externalCryptoCode, ALL[serviceName].CRYPTO)) { + throw new Error('Unsupported crypto: ' + externalCryptoCode) } const fiatSupported = ALL[serviceName].FIAT if (fiatSupported !== 'ALL_CURRENCIES' && !_.includes(fiatCode, fiatSupported)) { logger.info('Building a market for an unsupported fiat. Defaulting to EUR market') return cryptoCode + '/' + 'EUR' } - return cryptoCode + '/' + fiatCode + return externalCryptoCode + '/' + fiatCode } function verifyFiatSupport (fiatCode, serviceName) { diff --git a/new-lamassu-admin/src/pages/Services/schemas/galoy.js b/new-lamassu-admin/src/pages/Services/schemas/galoy.js new file mode 100644 index 00000000..ac6fa6b0 --- /dev/null +++ b/new-lamassu-admin/src/pages/Services/schemas/galoy.js @@ -0,0 +1,36 @@ +import * as Yup from 'yup' + +import SecretInputFormik from 'src/components/inputs/formik/SecretInput' +import TextInputFormik from 'src/components/inputs/formik/TextInput' + +import { secretTest } from './helper' + +export default { + code: 'galoy', + name: 'Galoy', + title: 'Galoy (Wallet)', + elements: [ + { + code: 'apiKey', + display: 'API Key', + component: TextInputFormik, + face: true, + long: true + }, + { + code: 'walletId', + display: 'Wallet ID', + component: SecretInputFormik + } + ], + getValidationSchema: account => { + return Yup.object().shape({ + apiKey: Yup.string('The API key must be a string') + .max(100, 'The API key is too long') + .required('The API key is required'), + walletId: Yup.string('The wallet id must be a string') + .max(100, 'The wallet id is too long') + .test(secretTest(account?.walletId)) + }) + } +} diff --git a/new-lamassu-admin/src/pages/Services/schemas/index.js b/new-lamassu-admin/src/pages/Services/schemas/index.js index 3ff44631..050ccdd2 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/index.js +++ b/new-lamassu-admin/src/pages/Services/schemas/index.js @@ -5,6 +5,7 @@ import bitstamp from './bitstamp' import blockcypher from './blockcypher' import cex from './cex' import ciphertrace from './ciphertrace' +import galoy from './galoy' import infura from './infura' import itbit from './itbit' import kraken from './kraken' @@ -16,6 +17,7 @@ import vonage from './vonage' export default { [bitgo.code]: bitgo, + [galoy.code]: galoy, [bitstamp.code]: bitstamp, [blockcypher.code]: blockcypher, [infura.code]: infura, diff --git a/new-lamassu-admin/src/pages/Wizard/components/Wallet/ChooseExchange.js b/new-lamassu-admin/src/pages/Wizard/components/Wallet/ChooseExchange.js index 5c3bb08b..d7225778 100644 --- a/new-lamassu-admin/src/pages/Wizard/components/Wallet/ChooseExchange.js +++ b/new-lamassu-admin/src/pages/Wizard/components/Wallet/ChooseExchange.js @@ -1,4 +1,5 @@ import { useQuery, useMutation } from '@apollo/react-hooks' +import { utils as coinUtils } from '@lamassu/coins' import { makeStyles } from '@material-ui/core' import gql from 'graphql-tag' import * as R from 'ramda' @@ -54,7 +55,7 @@ const ChooseExchange = ({ data: currentData, addData }) => { const accounts = data?.accounts ?? [] const accountsConfig = data?.accountsConfig ?? [] - const coin = currentData.coin + const coin = coinUtils.getExternalCryptoCode(currentData.coin) const exchanges = getItems(accountsConfig, accounts, 'exchange', coin) const submit = () => { diff --git a/new-lamassu-admin/src/pages/Wizard/components/Wallet/ChooseTicker.js b/new-lamassu-admin/src/pages/Wizard/components/Wallet/ChooseTicker.js index ca5e0955..8d320ea3 100644 --- a/new-lamassu-admin/src/pages/Wizard/components/Wallet/ChooseTicker.js +++ b/new-lamassu-admin/src/pages/Wizard/components/Wallet/ChooseTicker.js @@ -1,4 +1,5 @@ import { useQuery } from '@apollo/react-hooks' +import { utils as coinUtils } from '@lamassu/coins' import { makeStyles } from '@material-ui/core' import gql from 'graphql-tag' import * as R from 'ramda' @@ -34,7 +35,7 @@ const ChooseTicker = ({ data: currentData, addData }) => { const accounts = data?.accounts ?? [] const accountsConfig = data?.accountsConfig ?? [] - const coin = currentData.coin + const coin = coinUtils.getExternalCryptoCode(currentData.coin) const tickers = getItems(accountsConfig, accounts, 'ticker', coin) const submit = () => { diff --git a/new-lamassu-admin/src/pages/Wizard/components/Wallet/ChooseWallet.js b/new-lamassu-admin/src/pages/Wizard/components/Wallet/ChooseWallet.js index 94f78241..2f376783 100644 --- a/new-lamassu-admin/src/pages/Wizard/components/Wallet/ChooseWallet.js +++ b/new-lamassu-admin/src/pages/Wizard/components/Wallet/ChooseWallet.js @@ -39,7 +39,8 @@ const SAVE_ACCOUNTS = gql` } ` -const isConfigurable = it => R.contains(it)(['infura', 'bitgo', 'trongrid']) +const isConfigurable = it => + R.contains(it)(['infura', 'bitgo', 'trongrid', 'galoy']) const isLocalHosted = it => R.contains(it)([ @@ -167,6 +168,19 @@ const ChooseWallet = ({ data: currentData, addData }) => { /> )} + {selected === 'galoy' && ( + <> +

Enter wallet information

+ + + )} ) } From 76774a7d4f182f3bfbee7823cca23f7d61150d16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Tue, 12 Apr 2022 17:42:14 +0100 Subject: [PATCH 15/24] fix: revert old admin code changes --- lib/admin/config.js | 31 +++++++++++++++---------------- lib/admin/schemas/gajoy.json | 23 ----------------------- 2 files changed, 15 insertions(+), 39 deletions(-) delete mode 100644 lib/admin/schemas/gajoy.json diff --git a/lib/admin/config.js b/lib/admin/config.js index 4ad3c96d..642d55c9 100644 --- a/lib/admin/config.js +++ b/lib/admin/config.js @@ -13,6 +13,7 @@ const settingsLoader = require('./settings-loader') const configValidate = require('./config-validate') const jsonSchema = require('./lamassu-schema.json') + function fetchSchema () { return _.cloneDeep(jsonSchema) } @@ -147,18 +148,18 @@ const mapLanguage = lang => { const langNameArr = languageRec.lang[code] if (!langNameArr) return null const langName = langNameArr[0] - if (!country) return { code: lang, display: langName } - return { code: lang, display: `${langName} [${country}]` } + if (!country) return {code: lang, display: langName} + return {code: lang, display: `${langName} [${country}]`} } const supportedLanguages = languageRec.supported const languages = supportedLanguages.map(mapLanguage).filter(r => r) -const ALL_CRYPTOS = ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH', 'LN'] +const ALL_CRYPTOS = ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH'] const filterAccounts = (data, isDevMode) => { const notAllowed = ['mock-ticker', 'mock-wallet', 'mock-exchange', 'mock-sms', 'mock-id-verify', 'mock-zero-conf'] const filterOut = o => _.includes(o.code, notAllowed) - return isDevMode ? data : { ...data, accounts: _.filter(a => !filterOut(a), data.accounts) } + return isDevMode ? data : {...data, accounts: _.filter(a => !filterOut(a), data.accounts)} } function fetchData () { @@ -171,17 +172,16 @@ function fetchData () { { crypto: 'LTC', display: 'Litecoin' }, { crypto: 'DASH', display: 'Dash' }, { crypto: 'ZEC', display: 'Zcash' }, - { crypto: 'BCH', display: 'Bitcoin Cash' }, - { crypto: 'LN', display: 'Lightning Network' } + { crypto: 'BCH', display: 'Bitcoin Cash' } ], languages: languages, countries, accounts: [ - { code: 'bitpay', display: 'Bitpay', class: 'ticker', cryptos: ['BTC', 'BCH', 'LN'] }, - { code: 'kraken', display: 'Kraken', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH', 'LN'] }, - { code: 'bitstamp', display: 'Bitstamp', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'BCH', 'LN'] }, - { code: 'coinbase', display: 'Coinbase', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'BCH', 'ZEC', 'DASH', 'LN'] }, - { code: 'itbit', display: 'itBit', class: 'ticker', cryptos: ['BTC', 'ETH', 'LN'] }, + { code: 'bitpay', display: 'Bitpay', class: 'ticker', cryptos: ['BTC', 'BCH'] }, + { code: 'kraken', display: 'Kraken', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH'] }, + { code: 'bitstamp', display: 'Bitstamp', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'BCH'] }, + { code: 'coinbase', display: 'Coinbase', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'BCH', 'ZEC', 'DASH'] }, + { code: 'itbit', display: 'itBit', class: 'ticker', cryptos: ['BTC', 'ETH'] }, { code: 'mock-ticker', display: 'Mock (Caution!)', class: 'ticker', cryptos: ALL_CRYPTOS }, { code: 'bitcoind', display: 'bitcoind', class: 'wallet', cryptos: ['BTC'] }, { code: 'no-layer2', display: 'No Layer 2', class: 'layer2', cryptos: ALL_CRYPTOS }, @@ -192,10 +192,9 @@ function fetchData () { { code: 'dashd', display: 'dashd', class: 'wallet', cryptos: ['DASH'] }, { code: 'bitcoincashd', display: 'bitcoincashd', class: 'wallet', cryptos: ['BCH'] }, { code: 'bitgo', display: 'BitGo', class: 'wallet', cryptos: ['BTC', 'ZEC', 'LTC', 'BCH', 'DASH'] }, - { code: 'galoy', display: 'Galoy', class: 'wallet', cryptos: ['LN'] }, - { code: 'bitstamp', display: 'Bitstamp', class: 'exchange', cryptos: ['BTC', 'ETH', 'LTC', 'BCH', 'LN'] }, - { code: 'itbit', display: 'itBit', class: 'exchange', cryptos: ['BTC', 'ETH', 'LN'] }, - { code: 'kraken', display: 'Kraken', class: 'exchange', cryptos: ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH', 'LN'] }, + { code: 'bitstamp', display: 'Bitstamp', class: 'exchange', cryptos: ['BTC', 'ETH', 'LTC', 'BCH'] }, + { code: 'itbit', display: 'itBit', class: 'exchange', cryptos: ['BTC', 'ETH'] }, + { code: 'kraken', display: 'Kraken', class: 'exchange', cryptos: ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH'] }, { code: 'mock-wallet', display: 'Mock (Caution!)', class: 'wallet', cryptos: ALL_CRYPTOS }, { code: 'no-exchange', display: 'No exchange', class: 'exchange', cryptos: ALL_CRYPTOS }, { code: 'mock-exchange', display: 'Mock exchange', class: 'exchange', cryptos: ALL_CRYPTOS }, @@ -208,7 +207,7 @@ function fetchData () { { code: 'blockcypher', display: 'Blockcypher', class: 'zeroConf', cryptos: ['BTC'] }, { code: 'mock-zero-conf', display: 'Mock 0-conf', class: 'zeroConf', cryptos: ['BTC', 'ZEC', 'LTC', 'DASH', 'BCH', 'ETH'] } ], - machines: machineList.map(machine => ({ machine: machine.deviceId, display: machine.name })) + machines: machineList.map(machine => ({machine: machine.deviceId, display: machine.name})) })) .then((data) => { return filterAccounts(data, devMode) diff --git a/lib/admin/schemas/gajoy.json b/lib/admin/schemas/gajoy.json deleted file mode 100644 index 5076cc8a..00000000 --- a/lib/admin/schemas/gajoy.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "code": "galoy", - "display": "Galoy", - "fields": [ - { - "code": "apiKey", - "display": "API Key", - "fieldType": "string", - "secret": true, - "required": true, - "value": "" - }, - { - "code": "walletId", - "display": "Wallet ID", - "fieldType": "password", - "secret": true, - "required": true, - "value": "" - } - ] - } - \ No newline at end of file From 5576e300d9f3839cb432c282f3d0385168140e86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Tue, 12 Apr 2022 17:46:17 +0100 Subject: [PATCH 16/24] refactor: revert old config changes --- lib/admin/config.js | 70 ++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/lib/admin/config.js b/lib/admin/config.js index 642d55c9..328cadcf 100644 --- a/lib/admin/config.js +++ b/lib/admin/config.js @@ -167,45 +167,45 @@ function fetchData () { .then(machineList => ({ currencies: massageCurrencies(currencies), cryptoCurrencies: [ - { crypto: 'BTC', display: 'Bitcoin' }, - { crypto: 'ETH', display: 'Ethereum' }, - { crypto: 'LTC', display: 'Litecoin' }, - { crypto: 'DASH', display: 'Dash' }, - { crypto: 'ZEC', display: 'Zcash' }, - { crypto: 'BCH', display: 'Bitcoin Cash' } + {crypto: 'BTC', display: 'Bitcoin'}, + {crypto: 'ETH', display: 'Ethereum'}, + {crypto: 'LTC', display: 'Litecoin'}, + {crypto: 'DASH', display: 'Dash'}, + {crypto: 'ZEC', display: 'Zcash'}, + {crypto: 'BCH', display: 'Bitcoin Cash'} ], languages: languages, countries, accounts: [ - { code: 'bitpay', display: 'Bitpay', class: 'ticker', cryptos: ['BTC', 'BCH'] }, - { code: 'kraken', display: 'Kraken', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH'] }, - { code: 'bitstamp', display: 'Bitstamp', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'BCH'] }, - { code: 'coinbase', display: 'Coinbase', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'BCH', 'ZEC', 'DASH'] }, - { code: 'itbit', display: 'itBit', class: 'ticker', cryptos: ['BTC', 'ETH'] }, - { code: 'mock-ticker', display: 'Mock (Caution!)', class: 'ticker', cryptos: ALL_CRYPTOS }, - { code: 'bitcoind', display: 'bitcoind', class: 'wallet', cryptos: ['BTC'] }, - { code: 'no-layer2', display: 'No Layer 2', class: 'layer2', cryptos: ALL_CRYPTOS }, - { code: 'infura', display: 'Infura', class: 'wallet', cryptos: ['ETH'] }, - { code: 'geth', display: 'geth', class: 'wallet', cryptos: ['ETH'] }, - { code: 'zcashd', display: 'zcashd', class: 'wallet', cryptos: ['ZEC'] }, - { code: 'litecoind', display: 'litecoind', class: 'wallet', cryptos: ['LTC'] }, - { code: 'dashd', display: 'dashd', class: 'wallet', cryptos: ['DASH'] }, - { code: 'bitcoincashd', display: 'bitcoincashd', class: 'wallet', cryptos: ['BCH'] }, - { code: 'bitgo', display: 'BitGo', class: 'wallet', cryptos: ['BTC', 'ZEC', 'LTC', 'BCH', 'DASH'] }, - { code: 'bitstamp', display: 'Bitstamp', class: 'exchange', cryptos: ['BTC', 'ETH', 'LTC', 'BCH'] }, - { code: 'itbit', display: 'itBit', class: 'exchange', cryptos: ['BTC', 'ETH'] }, - { code: 'kraken', display: 'Kraken', class: 'exchange', cryptos: ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH'] }, - { code: 'mock-wallet', display: 'Mock (Caution!)', class: 'wallet', cryptos: ALL_CRYPTOS }, - { code: 'no-exchange', display: 'No exchange', class: 'exchange', cryptos: ALL_CRYPTOS }, - { code: 'mock-exchange', display: 'Mock exchange', class: 'exchange', cryptos: ALL_CRYPTOS }, - { code: 'mock-sms', display: 'Mock SMS', class: 'sms' }, - { code: 'mock-id-verify', display: 'Mock ID verifier', class: 'idVerifier' }, - { code: 'twilio', display: 'Twilio', class: 'sms' }, - { code: 'mailgun', display: 'Mailgun', class: 'email' }, - { code: 'all-zero-conf', display: 'Always 0-conf', class: 'zeroConf', cryptos: ['BTC', 'ZEC', 'LTC', 'DASH', 'BCH'] }, - { code: 'no-zero-conf', display: 'Always 1-conf', class: 'zeroConf', cryptos: ALL_CRYPTOS }, - { code: 'blockcypher', display: 'Blockcypher', class: 'zeroConf', cryptos: ['BTC'] }, - { code: 'mock-zero-conf', display: 'Mock 0-conf', class: 'zeroConf', cryptos: ['BTC', 'ZEC', 'LTC', 'DASH', 'BCH', 'ETH'] } + {code: 'bitpay', display: 'Bitpay', class: 'ticker', cryptos: ['BTC', 'BCH']}, + {code: 'kraken', display: 'Kraken', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH']}, + {code: 'bitstamp', display: 'Bitstamp', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'BCH']}, + {code: 'coinbase', display: 'Coinbase', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'BCH', 'ZEC', 'DASH']}, + {code: 'itbit', display: 'itBit', class: 'ticker', cryptos: ['BTC', 'ETH']}, + {code: 'mock-ticker', display: 'Mock (Caution!)', class: 'ticker', cryptos: ALL_CRYPTOS}, + {code: 'bitcoind', display: 'bitcoind', class: 'wallet', cryptos: ['BTC']}, + {code: 'no-layer2', display: 'No Layer 2', class: 'layer2', cryptos: ALL_CRYPTOS}, + {code: 'infura', display: 'Infura', class: 'wallet', cryptos: ['ETH']}, + {code: 'geth', display: 'geth', class: 'wallet', cryptos: ['ETH']}, + {code: 'zcashd', display: 'zcashd', class: 'wallet', cryptos: ['ZEC']}, + {code: 'litecoind', display: 'litecoind', class: 'wallet', cryptos: ['LTC']}, + {code: 'dashd', display: 'dashd', class: 'wallet', cryptos: ['DASH']}, + {code: 'bitcoincashd', display: 'bitcoincashd', class: 'wallet', cryptos: ['BCH']}, + {code: 'bitgo', display: 'BitGo', class: 'wallet', cryptos: ['BTC', 'ZEC', 'LTC', 'BCH', 'DASH']}, + {code: 'bitstamp', display: 'Bitstamp', class: 'exchange', cryptos: ['BTC', 'ETH', 'LTC', 'BCH']}, + {code: 'itbit', display: 'itBit', class: 'exchange', cryptos: ['BTC', 'ETH']}, + {code: 'kraken', display: 'Kraken', class: 'exchange', cryptos: ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH']}, + {code: 'mock-wallet', display: 'Mock (Caution!)', class: 'wallet', cryptos: ALL_CRYPTOS}, + {code: 'no-exchange', display: 'No exchange', class: 'exchange', cryptos: ALL_CRYPTOS}, + {code: 'mock-exchange', display: 'Mock exchange', class: 'exchange', cryptos: ALL_CRYPTOS}, + {code: 'mock-sms', display: 'Mock SMS', class: 'sms'}, + {code: 'mock-id-verify', display: 'Mock ID verifier', class: 'idVerifier'}, + {code: 'twilio', display: 'Twilio', class: 'sms'}, + {code: 'mailgun', display: 'Mailgun', class: 'email'}, + {code: 'all-zero-conf', display: 'Always 0-conf', class: 'zeroConf', cryptos: ['BTC', 'ZEC', 'LTC', 'DASH', 'BCH']}, + {code: 'no-zero-conf', display: 'Always 1-conf', class: 'zeroConf', cryptos: ALL_CRYPTOS}, + {code: 'blockcypher', display: 'Blockcypher', class: 'zeroConf', cryptos: ['BTC']}, + {code: 'mock-zero-conf', display: 'Mock 0-conf', class: 'zeroConf', cryptos: ['BTC', 'ZEC', 'LTC', 'DASH', 'BCH', 'ETH']} ], machines: machineList.map(machine => ({machine: machine.deviceId, display: machine.name})) })) From 638ca968d0b9d8e30b26084671cd1b0dd20318bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Tue, 12 Apr 2022 18:13:59 +0100 Subject: [PATCH 17/24] feat: add exchanges/tickers support for LN coin --- lib/plugins/common/ccxt.js | 4 ++-- lib/plugins/exchange/binance.js | 4 ++-- lib/plugins/exchange/binanceus.js | 4 ++-- lib/plugins/exchange/bitstamp.js | 4 ++-- lib/plugins/exchange/cex.js | 4 ++-- lib/plugins/exchange/itbit.js | 4 ++-- lib/plugins/exchange/kraken.js | 4 ++-- lib/plugins/ticker/bitpay.js | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/plugins/common/ccxt.js b/lib/plugins/common/ccxt.js index c4c54245..883c28b9 100644 --- a/lib/plugins/common/ccxt.js +++ b/lib/plugins/common/ccxt.js @@ -11,7 +11,7 @@ const bitpay = require('../ticker/bitpay') const binance = require('../exchange/binance') const logger = require('../../logger') -const { BTC, BCH, DASH, ETH, LTC, ZEC, USDT, TRX, USDT_TRON } = COINS +const { BTC, BCH, DASH, ETH, LTC, ZEC, USDT, TRX, USDT_TRON, LN } = COINS const ALL = { cex: cex, @@ -21,7 +21,7 @@ const ALL = { itbit: itbit, bitpay: bitpay, coinbase: { - CRYPTO: [BTC, ETH, LTC, DASH, ZEC, BCH, USDT, USDT_TRON, TRX], + CRYPTO: [BTC, ETH, LTC, DASH, ZEC, BCH, USDT, USDT_TRON, TRX, LN], FIAT: 'ALL_CURRENCIES' }, binance: binance diff --git a/lib/plugins/exchange/binance.js b/lib/plugins/exchange/binance.js index 0de4c9f9..8a45723c 100644 --- a/lib/plugins/exchange/binance.js +++ b/lib/plugins/exchange/binance.js @@ -4,8 +4,8 @@ const _ = require('lodash/fp') const { ORDER_TYPES } = require('./consts') const ORDER_TYPE = ORDER_TYPES.MARKET -const { BTC, BCH, XMR, ETH, LTC, ZEC } = COINS -const CRYPTO = [BTC, ETH, LTC, ZEC, BCH, XMR] +const { BTC, BCH, XMR, ETH, LTC, ZEC, LN } = COINS +const CRYPTO = [BTC, ETH, LTC, ZEC, BCH, XMR, LN] const FIAT = ['USD', 'EUR'] const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey'] diff --git a/lib/plugins/exchange/binanceus.js b/lib/plugins/exchange/binanceus.js index d68f78f5..ecf058b6 100644 --- a/lib/plugins/exchange/binanceus.js +++ b/lib/plugins/exchange/binanceus.js @@ -4,8 +4,8 @@ const _ = require('lodash/fp') const { ORDER_TYPES } = require('./consts') const ORDER_TYPE = ORDER_TYPES.MARKET -const { BTC, BCH, DASH, ETH, LTC, ZEC, USDT, USDT_TRON } = COINS -const CRYPTO = [BTC, ETH, LTC, DASH, ZEC, BCH, USDT, USDT_TRON] +const { BTC, BCH, DASH, ETH, LTC, ZEC, USDT, USDT_TRON, LN } = COINS +const CRYPTO = [BTC, ETH, LTC, DASH, ZEC, BCH, USDT, USDT_TRON, LN] const FIAT = ['USD'] const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey'] diff --git a/lib/plugins/exchange/bitstamp.js b/lib/plugins/exchange/bitstamp.js index 05b0e23a..5494ff1c 100644 --- a/lib/plugins/exchange/bitstamp.js +++ b/lib/plugins/exchange/bitstamp.js @@ -4,8 +4,8 @@ const _ = require('lodash/fp') const { ORDER_TYPES } = require('./consts') const ORDER_TYPE = ORDER_TYPES.MARKET -const { BTC, ETH, LTC, BCH, USDT } = COINS -const CRYPTO = [BTC, ETH, LTC, BCH, USDT ] +const { BTC, ETH, LTC, BCH, USDT, LN } = COINS +const CRYPTO = [BTC, ETH, LTC, BCH, USDT, LN] const FIAT = ['USD', 'EUR'] const AMOUNT_PRECISION = 8 const REQUIRED_CONFIG_FIELDS = ['key', 'secret', 'clientId'] diff --git a/lib/plugins/exchange/cex.js b/lib/plugins/exchange/cex.js index 03ef1f35..525eb427 100644 --- a/lib/plugins/exchange/cex.js +++ b/lib/plugins/exchange/cex.js @@ -4,8 +4,8 @@ const _ = require('lodash/fp') const { ORDER_TYPES } = require('./consts') const ORDER_TYPE = ORDER_TYPES.MARKET -const { BTC, BCH, DASH, ETH, LTC, USDT, TRX, USDT_TRON } = COINS -const CRYPTO = [BTC, ETH, LTC, DASH, BCH, USDT, TRX, USDT_TRON] +const { BTC, BCH, DASH, ETH, LTC, USDT, TRX, USDT_TRON, LN } = COINS +const CRYPTO = [BTC, ETH, LTC, DASH, BCH, USDT, TRX, USDT_TRON, LN] const FIAT = ['USD', 'EUR'] const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey'] diff --git a/lib/plugins/exchange/itbit.js b/lib/plugins/exchange/itbit.js index dcaa3d83..02572335 100644 --- a/lib/plugins/exchange/itbit.js +++ b/lib/plugins/exchange/itbit.js @@ -4,8 +4,8 @@ const { ORDER_TYPES } = require('./consts') const { COINS } = require('@lamassu/coins') const ORDER_TYPE = ORDER_TYPES.LIMIT -const { BTC, ETH, USDT } = COINS -const CRYPTO = [BTC, ETH, USDT] +const { BTC, ETH, USDT, LN } = COINS +const CRYPTO = [BTC, ETH, USDT, LN] const FIAT = ['USD'] const AMOUNT_PRECISION = 4 const REQUIRED_CONFIG_FIELDS = ['clientKey', 'clientSecret', 'userId', 'walletId'] diff --git a/lib/plugins/exchange/kraken.js b/lib/plugins/exchange/kraken.js index 856990b0..849af0e5 100644 --- a/lib/plugins/exchange/kraken.js +++ b/lib/plugins/exchange/kraken.js @@ -4,8 +4,8 @@ const { ORDER_TYPES } = require('./consts') const { COINS } = require('@lamassu/coins') const ORDER_TYPE = ORDER_TYPES.MARKET -const { BTC, BCH, DASH, ETH, LTC, ZEC, XMR, USDT, TRX, USDT_TRON } = COINS -const CRYPTO = [BTC, ETH, LTC, DASH, ZEC, BCH, XMR, USDT, TRX, USDT_TRON] +const { BTC, BCH, DASH, ETH, LTC, ZEC, XMR, USDT, TRX, USDT_TRON, LN } = COINS +const CRYPTO = [BTC, ETH, LTC, DASH, ZEC, BCH, XMR, USDT, TRX, USDT_TRON, LN] const FIAT = ['USD', 'EUR'] const AMOUNT_PRECISION = 6 const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey'] diff --git a/lib/plugins/ticker/bitpay.js b/lib/plugins/ticker/bitpay.js index f352131c..0952ab40 100644 --- a/lib/plugins/ticker/bitpay.js +++ b/lib/plugins/ticker/bitpay.js @@ -2,9 +2,9 @@ const axios = require('axios') const { COINS } = require('@lamassu/coins') const BN = require('../../bn') -const { BTC, BCH } = COINS +const { BTC, BCH, LN } = COINS -const CRYPTO = [BTC, BCH] +const CRYPTO = [BTC, BCH, LN] const FIAT = 'ALL_CURRENCIES' function ticker (fiatCode, cryptoCode) { From e4267d8aba103b222e97076d931fc4ae271c9d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Tue, 12 Apr 2022 19:37:37 +0100 Subject: [PATCH 18/24] refactor: revert old config changes --- lib/admin/config.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/admin/config.js b/lib/admin/config.js index 328cadcf..30ed4863 100644 --- a/lib/admin/config.js +++ b/lib/admin/config.js @@ -172,7 +172,8 @@ function fetchData () { {crypto: 'LTC', display: 'Litecoin'}, {crypto: 'DASH', display: 'Dash'}, {crypto: 'ZEC', display: 'Zcash'}, - {crypto: 'BCH', display: 'Bitcoin Cash'} + {crypto: 'BCH', display: 'Bitcoin Cash'}, + {crypto: 'LN', display: 'Lightning Network'} ], languages: languages, countries, From b65303e1ed37aac456aff8597a73d8565a2a837e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Tue, 12 Apr 2022 19:38:55 +0100 Subject: [PATCH 19/24] refactor: remove LN from old crypto list --- lib/admin/config.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/admin/config.js b/lib/admin/config.js index 30ed4863..328cadcf 100644 --- a/lib/admin/config.js +++ b/lib/admin/config.js @@ -172,8 +172,7 @@ function fetchData () { {crypto: 'LTC', display: 'Litecoin'}, {crypto: 'DASH', display: 'Dash'}, {crypto: 'ZEC', display: 'Zcash'}, - {crypto: 'BCH', display: 'Bitcoin Cash'}, - {crypto: 'LN', display: 'Lightning Network'} + {crypto: 'BCH', display: 'Bitcoin Cash'} ], languages: languages, countries, From d0b960fd6ad7690736e2a0de765e7674ef5a1ab7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Wed, 13 Apr 2022 22:13:39 +0100 Subject: [PATCH 20/24] feat: build ticker for LN coin --- lib/plugins/wallet/galoy/galoy.js | 76 +++++++++++++------ lib/ticker.js | 14 ++-- .../src/pages/Services/schemas/galoy.js | 2 +- 3 files changed, 62 insertions(+), 30 deletions(-) diff --git a/lib/plugins/wallet/galoy/galoy.js b/lib/plugins/wallet/galoy/galoy.js index 433a2ea2..0ee80fa6 100644 --- a/lib/plugins/wallet/galoy/galoy.js +++ b/lib/plugins/wallet/galoy/galoy.js @@ -1,6 +1,8 @@ const _ = require('lodash/fp') const invoice = require('@node-lightning/invoice') const axios = require('axios') +const { utils: coinUtils } = require('@lamassu/coins') + const NAME = 'LN' const SUPPORTED_COINS = ['LN', 'BTC'] const TX_PENDING = 'PENDING' @@ -148,14 +150,19 @@ function sendFundsLN (walletId, invoice, token) { function sendCoins (account, tx, settings, operatorId) { const { toAddress, cryptoAtoms, cryptoCode } = tx + const externalCryptoCode = coinUtils.getExternalCryptoCode(cryptoCode) return checkCryptoCode(cryptoCode) - .then(() => getGaloyAccount(account.authToken)) + .then(() => getGaloyAccount(account.apiKey)) .then(galoyAccount => { - const wallet = _.head(_.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === galoyAccount.defaultWalletId)(galoyAccount.wallets)) + const wallet = _.head( + _.filter(wallet => wallet.walletCurrency === externalCryptoCode && + wallet.id === galoyAccount.defaultWalletId && + wallet.id === account.walletId)(galoyAccount.wallets) + ) if (isLightning(toAddress)) { - return sendFundsLN(wallet.id, toAddress, account.authToken) + return sendFundsLN(wallet.id, toAddress, account.apiKey) } - return sendFundsOnChain(wallet.id, toAddress, cryptoAtoms, account.authToken) + return sendFundsOnChain(wallet.id, toAddress, cryptoAtoms, account.apiKey) }) .then(result => { switch (result.status) { @@ -163,8 +170,12 @@ function sendCoins (account, tx, settings, operatorId) { throw new Error('Transaction already exists!') case 'FAILURE': throw new Error('Transaction failed!') - default: + case 'SUCCESS': return '' + case 'PENDING': + return '' + default: + throw new Error(`Transaction failed: ${_.head(result.errors).message}`) } }) } @@ -212,67 +223,88 @@ function newInvoice (walletId, cryptoAtoms, token) { } function balance (account, cryptoCode, settings, operatorId) { + const externalCryptoCode = coinUtils.getExternalCryptoCode(cryptoCode) return checkCryptoCode(cryptoCode) - .then(() => getGaloyAccount(account.authToken)) + .then(() => getGaloyAccount(account.apiKey)) .then(galoyAccount => { // account has a list of wallets, should we consider the balance of each one? // for now we'll get the first BTC wallet that matches the defaultWalletId - const wallet = _.head(_.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === galoyAccount.defaultWalletId)(galoyAccount.wallets)) + const wallet = _.head( + _.filter( + wallet => wallet.walletCurrency === externalCryptoCode && + wallet.id === account.walletId)(galoyAccount.wallets) + ) return new BN(wallet.balance || 0) }) } function newAddress (account, info, tx, settings, operatorId) { const { cryptoAtoms, cryptoCode } = tx + const externalCryptoCode = coinUtils.getExternalCryptoCode(cryptoCode) return checkCryptoCode(cryptoCode) - .then(() => getGaloyAccount(account.authToken)) + .then(() => getGaloyAccount(account.apiKey)) .then(galoyAccount => { - const wallet = _.head(_.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === galoyAccount.defaultWalletId)(galoyAccount.wallets)) + const wallet = _.head( + _.filter(wallet => wallet.walletCurrency === externalCryptoCode && + wallet.id === galoyAccount.defaultWalletId && + wallet.id === account.walletId)(galoyAccount.wallets) + ) const promises = [ - newOnChainAddress(wallet.id, account.authToken), - newInvoice(wallet.id, cryptoAtoms, account.authToken) + newOnChainAddress(wallet.id, account.apiKey), + newInvoice(wallet.id, cryptoAtoms, account.apiKey) ] return Promise.all(promises) }) .then(([onChainAddress, invoice]) => { - return `bitcoin:${onChainAddress}?amount=${cryptoAtoms}?lightning=${invoice}` + return `bitcoin:${onChainAddress}?amount=${cryptoAtoms}&lightning=${invoice}` }) } function getStatus (account, tx, requested, settings, operatorId) { const { toAddress, cryptoAtoms, cryptoCode } = tx - const mapStatus = status => { - if (status === TX_PENDING) return 'authorized' - if (status === TX_SUCCESS) return 'confirmed' + const mapStatus = tx => { + if (!tx) return 'notSeen' + if (tx.node.status === TX_PENDING) return 'authorized' + if (tx.node.status === TX_SUCCESS) return 'confirmed' return 'notSeen' } + const externalCryptoCode = coinUtils.getExternalCryptoCode(cryptoCode) return checkCryptoCode(cryptoCode) - .then(() => getGaloyAccount(account.authToken)) + .then(() => getGaloyAccount(account.apiKey)) .then(galoyAccount => { - const wallet = _.head(_.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === galoyAccount.defaultWalletId)(galoyAccount.wallets)) + const wallet = _.head( + _.filter(wallet => wallet.walletCurrency === externalCryptoCode && + wallet.id === galoyAccount.defaultWalletId && + wallet.id === account.walletId)(galoyAccount.wallets) + ) const transactions = wallet.transactions.edges if (isLightning(toAddress)) { const paymentHash = invoice.decode(toAddress).paymentHash.toString('hex') const transaction = _.head(_.filter(tx => tx.node.initiationVia.paymentHash === paymentHash && tx.node.direction === 'RECEIVE')(transactions)) - return { receivedCryptoAtoms: cryptoAtoms, status: mapStatus(transaction.node.status) } + return { receivedCryptoAtoms: cryptoAtoms, status: mapStatus(transaction) } } // On-chain tx const transaction = _.head(_.filter(tx => tx.node.initiationVia.address === toAddress)(transactions)) - return { receivedCryptoAtoms: cryptoAtoms, status: mapStatus(transaction.node.status) } + return { receivedCryptoAtoms: cryptoAtoms, status: mapStatus(transaction) } }) } function newFunding (account, cryptoCode, settings, operatorId) { + const externalCryptoCode = coinUtils.getExternalCryptoCode(cryptoCode) // Regular BTC address return checkCryptoCode(cryptoCode) - .then(() => getGaloyAccount(account.authToken)) + .then(() => getGaloyAccount(account.apiKey)) .then(galoyAccount => { - const wallet = _.head(_.filter(wallet => wallet.walletCurrency === cryptoCode && wallet.id === galoyAccount.defaultWalletId)(galoyAccount.wallets)) + const wallet = _.head( + _.filter(wallet => wallet.walletCurrency === externalCryptoCode && + wallet.id === galoyAccount.defaultWalletId && + wallet.id === account.walletId)(galoyAccount.wallets) + ) const pendingBalance = _.sumBy(tx => { if (tx.node.status === TX_PENDING) return tx.node.settlementAmount return 0 })(wallet.transactions.edges) - return newOnChainAddress(wallet.id, account.authToken) + return newOnChainAddress(wallet.id, account.apiKey) .then(onChainAddress => [onChainAddress, wallet.balance, pendingBalance]) }) .then(([onChainAddress, balance, pendingBalance]) => { diff --git a/lib/ticker.js b/lib/ticker.js index 389a0428..9475b71d 100644 --- a/lib/ticker.js +++ b/lib/ticker.js @@ -2,6 +2,7 @@ const { utils: coinUtils } = require('@lamassu/coins') const _ = require('lodash/fp') const mem = require('mem') const configManager = require('./new-config-manager') +const { utils: coinUtils } = require('@lamassu/coins') const logger = require('./logger') const lastRate = {} @@ -36,16 +37,15 @@ function _getRates (settings, fiatCode, cryptoCode) { }) } -function buildTicker (fiatCode, _cryptoCode, tickerName) { - const fiatPeggedEquivalent = _.includes(fiatCode, _.keys(PEGGED_FIAT_CURRENCIES)) +function buildTicker (fiatCode, cryptoCode, tickerName) { + fiatCode = _.includes(fiatCode, _.keys(PEGGED_FIAT_CURRENCIES)) ? PEGGED_FIAT_CURRENCIES[fiatCode] : fiatCode + cryptoCode = coinUtils.getEquivalentCode(cryptoCode) - const cryptoCode = coinUtils.getEquivalentCode(_cryptoCode) - - if (tickerName === 'bitpay') return bitpay.ticker(fiatPeggedEquivalent, cryptoCode) - if (tickerName === 'mock-ticker') return mockTicker.ticker(fiatPeggedEquivalent, cryptoCode) - return ccxt.ticker(fiatPeggedEquivalent, cryptoCode, tickerName) + if (tickerName === 'bitpay') return bitpay.ticker(fiatCode, cryptoCode) + if (tickerName === 'mock-ticker') return mockTicker.ticker(fiatCode, cryptoCode) + return ccxt.ticker(fiatCode, cryptoCode, tickerName) } const getRates = mem(_getRates, { diff --git a/new-lamassu-admin/src/pages/Services/schemas/galoy.js b/new-lamassu-admin/src/pages/Services/schemas/galoy.js index ac6fa6b0..b2d2bdf5 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/galoy.js +++ b/new-lamassu-admin/src/pages/Services/schemas/galoy.js @@ -26,7 +26,7 @@ export default { getValidationSchema: account => { return Yup.object().shape({ apiKey: Yup.string('The API key must be a string') - .max(100, 'The API key is too long') + .max(200, 'The API key is too long') .required('The API key is required'), walletId: Yup.string('The wallet id must be a string') .max(100, 'The wallet id is too long') From 81ef96a6705853629b4ac7d81674e645e153af42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Tue, 19 Apr 2022 13:47:35 +0100 Subject: [PATCH 21/24] fix: parse address before get tx status --- lib/plugins/wallet/galoy/galoy.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/plugins/wallet/galoy/galoy.js b/lib/plugins/wallet/galoy/galoy.js index 0ee80fa6..f9302020 100644 --- a/lib/plugins/wallet/galoy/galoy.js +++ b/lib/plugins/wallet/galoy/galoy.js @@ -269,6 +269,7 @@ function getStatus (account, tx, requested, settings, operatorId) { return 'notSeen' } const externalCryptoCode = coinUtils.getExternalCryptoCode(cryptoCode) + const address = coinUtils.parseUrl(address) return checkCryptoCode(cryptoCode) .then(() => getGaloyAccount(account.apiKey)) .then(galoyAccount => { @@ -278,13 +279,13 @@ function getStatus (account, tx, requested, settings, operatorId) { wallet.id === account.walletId)(galoyAccount.wallets) ) const transactions = wallet.transactions.edges - if (isLightning(toAddress)) { - const paymentHash = invoice.decode(toAddress).paymentHash.toString('hex') + if (isLightning(address)) { + const paymentHash = invoice.decode(address).paymentHash.toString('hex') const transaction = _.head(_.filter(tx => tx.node.initiationVia.paymentHash === paymentHash && tx.node.direction === 'RECEIVE')(transactions)) return { receivedCryptoAtoms: cryptoAtoms, status: mapStatus(transaction) } } // On-chain tx - const transaction = _.head(_.filter(tx => tx.node.initiationVia.address === toAddress)(transactions)) + const transaction = _.head(_.filter(tx => tx.node.initiationVia.address === address)(transactions)) return { receivedCryptoAtoms: cryptoAtoms, status: mapStatus(transaction) } }) } From d72fc97f98b154d3833ac79223f9019a18e9520d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Tue, 26 Apr 2022 22:21:58 +0100 Subject: [PATCH 22/24] fix: remove unnecessary code --- lib/plugins/wallet/galoy/galoy.js | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/lib/plugins/wallet/galoy/galoy.js b/lib/plugins/wallet/galoy/galoy.js index f9302020..af877034 100644 --- a/lib/plugins/wallet/galoy/galoy.js +++ b/lib/plugins/wallet/galoy/galoy.js @@ -17,15 +17,12 @@ function request (graphqlQuery, token) { 'content-type': 'application/json', 'Authorization': `Bearer ${token}` } - return Promise.resolve(true) - .then(() => { - return axios({ - method: 'post', - url: URI, - headers: headers, - data: graphqlQuery - }) - }) + return axios({ + method: 'post', + url: URI, + headers: headers, + data: graphqlQuery + }) .then(r => { if (r.error) throw r.error return r.data @@ -45,7 +42,6 @@ function getGaloyAccount (token) { 'operationName': 'me', 'query': `query me { me { - createdAt defaultAccount { defaultWalletId wallets { @@ -55,7 +51,6 @@ function getGaloyAccount (token) { transactions { edges { node { - createdAt direction id settlementAmount @@ -91,9 +86,6 @@ function getGaloyAccount (token) { } } id - phone - twoFAEnabled - username } }`, 'variables': {} @@ -269,7 +261,7 @@ function getStatus (account, tx, requested, settings, operatorId) { return 'notSeen' } const externalCryptoCode = coinUtils.getExternalCryptoCode(cryptoCode) - const address = coinUtils.parseUrl(address) + const address = coinUtils.parseUrl(toAddress) return checkCryptoCode(cryptoCode) .then(() => getGaloyAccount(account.apiKey)) .then(galoyAccount => { From 6cd72aed0082ddb401ad654f07c17ec901906dae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Tue, 26 Apr 2022 22:25:33 +0100 Subject: [PATCH 23/24] chore: simplify filter function --- lib/new-admin/services/funding.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/new-admin/services/funding.js b/lib/new-admin/services/funding.js index 8f748696..38436189 100644 --- a/lib/new-admin/services/funding.js +++ b/lib/new-admin/services/funding.js @@ -57,7 +57,7 @@ const reflect = p => p.then(value => ({ value, status: 'fulfilled' }), error => function getFunding () { return settingsLoader.loadLatest().then(settings => { - const cryptoCodes = _.filter(code => coinUtils.getExternalCryptoCode(code) === code)(configManager.getAllCryptoCurrencies(settings.config)) + const cryptoCodes = _.filter(code => coinUtils.getExternalCryptoCode(code) === code, configManager.getAllCryptoCurrencies(settings.config)) const fiatCode = configManager.getGlobalLocale(settings.config).fiatCurrency const pareCoins = c => _.includes(c.cryptoCode, cryptoCodes) const cryptoCurrencies = coinUtils.cryptoCurrencies() From 04cd7d758e82a9cc967ce673ac272995ded28463 Mon Sep 17 00:00:00 2001 From: siiky Date: Thu, 28 Sep 2023 18:55:16 +0100 Subject: [PATCH 24/24] chore: bump `@node-lightning/invoice` --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 051eba5e..59dbd8ec 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "@ethereumjs/tx": "^3.5.1", "@graphql-tools/merge": "^6.2.5", "@lamassu/coins": "v1.3.3", - "@node-lightning/invoice": "0.22.1", + "@node-lightning/invoice": "0.28.0", "@simplewebauthn/server": "^3.0.0", "@vonage/auth": "^1.5.0", "@vonage/sms": "^1.7.0",