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] 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')