feat: build ticker for LN coin
This commit is contained in:
parent
b65303e1ed
commit
d0b960fd6a
3 changed files with 62 additions and 30 deletions
|
|
@ -1,6 +1,8 @@
|
||||||
const _ = require('lodash/fp')
|
const _ = require('lodash/fp')
|
||||||
const invoice = require('@node-lightning/invoice')
|
const invoice = require('@node-lightning/invoice')
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
|
const { utils: coinUtils } = require('@lamassu/coins')
|
||||||
|
|
||||||
const NAME = 'LN'
|
const NAME = 'LN'
|
||||||
const SUPPORTED_COINS = ['LN', 'BTC']
|
const SUPPORTED_COINS = ['LN', 'BTC']
|
||||||
const TX_PENDING = 'PENDING'
|
const TX_PENDING = 'PENDING'
|
||||||
|
|
@ -148,14 +150,19 @@ function sendFundsLN (walletId, invoice, token) {
|
||||||
|
|
||||||
function sendCoins (account, tx, settings, operatorId) {
|
function sendCoins (account, tx, settings, operatorId) {
|
||||||
const { toAddress, cryptoAtoms, cryptoCode } = tx
|
const { toAddress, cryptoAtoms, cryptoCode } = tx
|
||||||
|
const externalCryptoCode = coinUtils.getExternalCryptoCode(cryptoCode)
|
||||||
return checkCryptoCode(cryptoCode)
|
return checkCryptoCode(cryptoCode)
|
||||||
.then(() => getGaloyAccount(account.authToken))
|
.then(() => getGaloyAccount(account.apiKey))
|
||||||
.then(galoyAccount => {
|
.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)) {
|
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 => {
|
.then(result => {
|
||||||
switch (result.status) {
|
switch (result.status) {
|
||||||
|
|
@ -163,8 +170,12 @@ function sendCoins (account, tx, settings, operatorId) {
|
||||||
throw new Error('Transaction already exists!')
|
throw new Error('Transaction already exists!')
|
||||||
case 'FAILURE':
|
case 'FAILURE':
|
||||||
throw new Error('Transaction failed!')
|
throw new Error('Transaction failed!')
|
||||||
default:
|
case 'SUCCESS':
|
||||||
return '<galoy transaction>'
|
return '<galoy transaction>'
|
||||||
|
case 'PENDING':
|
||||||
|
return '<galoy transaction>'
|
||||||
|
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) {
|
function balance (account, cryptoCode, settings, operatorId) {
|
||||||
|
const externalCryptoCode = coinUtils.getExternalCryptoCode(cryptoCode)
|
||||||
return checkCryptoCode(cryptoCode)
|
return checkCryptoCode(cryptoCode)
|
||||||
.then(() => getGaloyAccount(account.authToken))
|
.then(() => getGaloyAccount(account.apiKey))
|
||||||
.then(galoyAccount => {
|
.then(galoyAccount => {
|
||||||
// account has a list of wallets, should we consider the balance of each one?
|
// 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
|
// 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)
|
return new BN(wallet.balance || 0)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function newAddress (account, info, tx, settings, operatorId) {
|
function newAddress (account, info, tx, settings, operatorId) {
|
||||||
const { cryptoAtoms, cryptoCode } = tx
|
const { cryptoAtoms, cryptoCode } = tx
|
||||||
|
const externalCryptoCode = coinUtils.getExternalCryptoCode(cryptoCode)
|
||||||
return checkCryptoCode(cryptoCode)
|
return checkCryptoCode(cryptoCode)
|
||||||
.then(() => getGaloyAccount(account.authToken))
|
.then(() => getGaloyAccount(account.apiKey))
|
||||||
.then(galoyAccount => {
|
.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 = [
|
const promises = [
|
||||||
newOnChainAddress(wallet.id, account.authToken),
|
newOnChainAddress(wallet.id, account.apiKey),
|
||||||
newInvoice(wallet.id, cryptoAtoms, account.authToken)
|
newInvoice(wallet.id, cryptoAtoms, account.apiKey)
|
||||||
]
|
]
|
||||||
return Promise.all(promises)
|
return Promise.all(promises)
|
||||||
})
|
})
|
||||||
.then(([onChainAddress, invoice]) => {
|
.then(([onChainAddress, invoice]) => {
|
||||||
return `bitcoin:${onChainAddress}?amount=${cryptoAtoms}?lightning=${invoice}`
|
return `bitcoin:${onChainAddress}?amount=${cryptoAtoms}&lightning=${invoice}`
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStatus (account, tx, requested, settings, operatorId) {
|
function getStatus (account, tx, requested, settings, operatorId) {
|
||||||
const { toAddress, cryptoAtoms, cryptoCode } = tx
|
const { toAddress, cryptoAtoms, cryptoCode } = tx
|
||||||
const mapStatus = status => {
|
const mapStatus = tx => {
|
||||||
if (status === TX_PENDING) return 'authorized'
|
if (!tx) return 'notSeen'
|
||||||
if (status === TX_SUCCESS) return 'confirmed'
|
if (tx.node.status === TX_PENDING) return 'authorized'
|
||||||
|
if (tx.node.status === TX_SUCCESS) return 'confirmed'
|
||||||
return 'notSeen'
|
return 'notSeen'
|
||||||
}
|
}
|
||||||
|
const externalCryptoCode = coinUtils.getExternalCryptoCode(cryptoCode)
|
||||||
return checkCryptoCode(cryptoCode)
|
return checkCryptoCode(cryptoCode)
|
||||||
.then(() => getGaloyAccount(account.authToken))
|
.then(() => getGaloyAccount(account.apiKey))
|
||||||
.then(galoyAccount => {
|
.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
|
const transactions = wallet.transactions.edges
|
||||||
if (isLightning(toAddress)) {
|
if (isLightning(toAddress)) {
|
||||||
const paymentHash = invoice.decode(toAddress).paymentHash.toString('hex')
|
const paymentHash = invoice.decode(toAddress).paymentHash.toString('hex')
|
||||||
const transaction = _.head(_.filter(tx => tx.node.initiationVia.paymentHash === paymentHash && tx.node.direction === 'RECEIVE')(transactions))
|
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
|
// On-chain tx
|
||||||
const transaction = _.head(_.filter(tx => tx.node.initiationVia.address === toAddress)(transactions))
|
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) {
|
function newFunding (account, cryptoCode, settings, operatorId) {
|
||||||
|
const externalCryptoCode = coinUtils.getExternalCryptoCode(cryptoCode)
|
||||||
// Regular BTC address
|
// Regular BTC address
|
||||||
return checkCryptoCode(cryptoCode)
|
return checkCryptoCode(cryptoCode)
|
||||||
.then(() => getGaloyAccount(account.authToken))
|
.then(() => getGaloyAccount(account.apiKey))
|
||||||
.then(galoyAccount => {
|
.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 => {
|
const pendingBalance = _.sumBy(tx => {
|
||||||
if (tx.node.status === TX_PENDING) return tx.node.settlementAmount
|
if (tx.node.status === TX_PENDING) return tx.node.settlementAmount
|
||||||
return 0
|
return 0
|
||||||
})(wallet.transactions.edges)
|
})(wallet.transactions.edges)
|
||||||
return newOnChainAddress(wallet.id, account.authToken)
|
return newOnChainAddress(wallet.id, account.apiKey)
|
||||||
.then(onChainAddress => [onChainAddress, wallet.balance, pendingBalance])
|
.then(onChainAddress => [onChainAddress, wallet.balance, pendingBalance])
|
||||||
})
|
})
|
||||||
.then(([onChainAddress, balance, pendingBalance]) => {
|
.then(([onChainAddress, balance, pendingBalance]) => {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ const { utils: coinUtils } = require('@lamassu/coins')
|
||||||
const _ = require('lodash/fp')
|
const _ = require('lodash/fp')
|
||||||
const mem = require('mem')
|
const mem = require('mem')
|
||||||
const configManager = require('./new-config-manager')
|
const configManager = require('./new-config-manager')
|
||||||
|
const { utils: coinUtils } = require('@lamassu/coins')
|
||||||
const logger = require('./logger')
|
const logger = require('./logger')
|
||||||
const lastRate = {}
|
const lastRate = {}
|
||||||
|
|
||||||
|
|
@ -36,16 +37,15 @@ function _getRates (settings, fiatCode, cryptoCode) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildTicker (fiatCode, _cryptoCode, tickerName) {
|
function buildTicker (fiatCode, cryptoCode, tickerName) {
|
||||||
const fiatPeggedEquivalent = _.includes(fiatCode, _.keys(PEGGED_FIAT_CURRENCIES))
|
fiatCode = _.includes(fiatCode, _.keys(PEGGED_FIAT_CURRENCIES))
|
||||||
? PEGGED_FIAT_CURRENCIES[fiatCode]
|
? PEGGED_FIAT_CURRENCIES[fiatCode]
|
||||||
: fiatCode
|
: fiatCode
|
||||||
|
cryptoCode = coinUtils.getEquivalentCode(cryptoCode)
|
||||||
|
|
||||||
const cryptoCode = coinUtils.getEquivalentCode(_cryptoCode)
|
if (tickerName === 'bitpay') return bitpay.ticker(fiatCode, cryptoCode)
|
||||||
|
if (tickerName === 'mock-ticker') return mockTicker.ticker(fiatCode, cryptoCode)
|
||||||
if (tickerName === 'bitpay') return bitpay.ticker(fiatPeggedEquivalent, cryptoCode)
|
return ccxt.ticker(fiatCode, cryptoCode, tickerName)
|
||||||
if (tickerName === 'mock-ticker') return mockTicker.ticker(fiatPeggedEquivalent, cryptoCode)
|
|
||||||
return ccxt.ticker(fiatPeggedEquivalent, cryptoCode, tickerName)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const getRates = mem(_getRates, {
|
const getRates = mem(_getRates, {
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ export default {
|
||||||
getValidationSchema: account => {
|
getValidationSchema: account => {
|
||||||
return Yup.object().shape({
|
return Yup.object().shape({
|
||||||
apiKey: Yup.string('The API key must be a string')
|
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'),
|
.required('The API key is required'),
|
||||||
walletId: Yup.string('The wallet id must be a string')
|
walletId: Yup.string('The wallet id must be a string')
|
||||||
.max(100, 'The wallet id is too long')
|
.max(100, 'The wallet id is too long')
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue