feat: build ticker for LN coin

This commit is contained in:
José Oliveira 2022-04-13 22:13:39 +01:00 committed by siiky
parent b65303e1ed
commit d0b960fd6a
3 changed files with 62 additions and 30 deletions

View file

@ -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 '<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) {
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]) => {

View file

@ -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, {