Skip to content

Commit

Permalink
Fabo/improve emoney loading (#494)
Browse files Browse the repository at this point in the history
* allow to wait for data to be ready

* wait for data to be ready

* improve blockHandler logic

* keep store in cosmos source

* centralize emoney exchange queries

* fixed balances nto available

* precalculate all exchange rates

* remove mock values

* add sentry to nested block handler

* linted

* keep old emoney tokens for now

Co-authored-by: Bitcoinera <[email protected]>
  • Loading branch information
faboweb and Bitcoinera authored Mar 24, 2020
1 parent b066bcd commit 1a4cf11
Show file tree
Hide file tree
Showing 2 changed files with 176 additions and 156 deletions.
145 changes: 72 additions & 73 deletions lib/reducers/emoneyV0-reducers.js
Original file line number Diff line number Diff line change
@@ -1,106 +1,105 @@
const terraV3Reducers = require('./terraV3-reducers')
const BigNumber = require('bignumber.js')
const fetch = require('node-fetch')
const _ = require('lodash')
const EMoneyAPIUrl = `https://api.e-money.com/v1/`
const exchangeAPIURL = `https://api.exchangeratesapi.io/latest?`
const Sentry = require('@sentry/node')

async function totalBackedValueReducer(totalBackedValue) {
const exchangeRates = await fetchTokenExchangeRates()
const token = `e`.concat(totalBackedValue.denom.substring(1))
const ticker = totalBackedValue.denom.substring(1).toUpperCase()
// First we calculate the fiat net value of the token's total supply in it counterpart
// fiat currency
const fiatValue = exchangeRates[token]
? BigNumber(totalBackedValue.amount)
.div(1000000)
.times(exchangeRates[token][ticker])
.toNumber()
: null
// Now that we have its net fiat value, we transform this value into euro
const { rates } = await fetchFiatExchangeRates(`EUR`, ticker)
const eurRate = ticker === `EUR` ? 1 : rates[ticker]
return (totalBackedValue = {
...totalBackedValue,
amount: exchangeRates[token]
? BigNumber(totalBackedValue.amount).times(
Object.values(exchangeRates[token])[0]
)
: BigNumber(totalBackedValue.amount),
// The total net EUR value of the token's total supply equals its net value in its
// counterpart fiat currency times this fiat currency's EUR rate
eurValue: fiatValue * eurRate
})
}
async function totalBackedValueReducer(
totalBackedValue,
exchangeRates,
reducers
) {
const aggregatingCurrency = `EUR`
const lunieCoin = reducers.coinReducer(totalBackedValue)

async function fetchTokenExchangeRates() {
return await fetch(`${EMoneyAPIUrl}rates.json`)
.then(r => r.json())
.catch(err => {
Sentry.withScope(function(scope) {
scope.setExtra('fetch', `${EMoneyAPIUrl}rates.json`)
Sentry.captureException(err)
})
})
// The total net EUR value of the token's total supply
const fiatValue = BigNumber(lunieCoin.amount)
.times(exchangeRates[lunieCoin.denom][aggregatingCurrency])
.toNumber()
return {
...lunieCoin,
eurValue: fiatValue
}
}

async function fetchFiatExchangeRates(selectedFiatCurrency, ticker) {
return await fetch(
`${exchangeAPIURL}base=${selectedFiatCurrency}&symbols=${ticker}`
async function getTotalNetworkAnnualRewards(inflations, totalBackedValues) {
// Now we need to multiply each total supply of backed tokens with its corresponding
// inflation
const totalBackedValueDictionary = _.keyBy(
totalBackedValues.map(totalBackedValue => ({
...totalBackedValue,
denom: totalBackedValue.denom.toLowerCase() // inflation response uses lower case denoms
})),
'denom'
)
.then(r => r.json())
.catch(err => {
Sentry.withScope(function(scope) {
scope.setExtra(
'fetch',
`${exchangeAPIURL}base=${selectedFiatCurrency}&symbols=${ticker}`
)
Sentry.captureException(err)
})
})
const rewardsSumInEur = inflations.reduce((sum, inflation) => {
return BigNumber(sum).plus(
BigNumber(inflation.inflation).times(
totalBackedValueDictionary[inflation.denom].eurValue // we use the eur value to be able to sum up the individual token values
)
)
}, 0)

return rewardsSumInEur
}

async function expectedRewardsPerToken(
validator,
commission,
inflations,
totalBackedValues
totalNetworkAnnualRewards,
exchangeRates
) {
const aggregatingCurrency = 'EUR'
const stakingToken = 'NGM'

const percentOfAllEligibleStake = validator.votingPower
const totalStakeToValidator = validator.tokens // used to answer the question "How many rewards per ONE token invested?"
const percentOfAllRewardsPerToken = BigNumber(percentOfAllEligibleStake)
.times(BigNumber(1).minus(BigNumber(commission)))
.div(BigNumber(totalStakeToValidator))

// Now we need to multiply each total supply of backed tokens with its corresponding
// inflation
const totalBackedValueDictionary = _.keyBy(totalBackedValues, 'denom')
const rewardsSumInEur = inflations.reduce((sum, inflation) => {
return BigNumber(sum).plus(
BigNumber(inflation.inflation).times(
totalBackedValueDictionary[inflation.denom].eurValue // we use the eur value to be able to sum up the individual token values
)
)
}, 0)

// now we calculate the total rewards in eur per token delegated to the validator
const totalEURGainsPerTokenInvested = BigNumber(rewardsSumInEur).times(
percentOfAllRewardsPerToken
)
const totalEURGainsPerTokenInvested = BigNumber(
totalNetworkAnnualRewards
).times(percentOfAllRewardsPerToken)

// How many NGM tokens can we buy with the total gain in EUR we make in a year's time?
// 0.50€ is the price the NGM tokens will be first sold. Therefore, this is the official value
// until they reach an exchange
const pricePerNGM = 0.5
const ngmGains = totalEURGainsPerTokenInvested / pricePerNGM
const pricePerNGM = exchangeRates[stakingToken][aggregatingCurrency]
const ngmGains = totalEURGainsPerTokenInvested.div(pricePerNGM)

return ngmGains.toFixed(4) // we don't need more then a precision of 2 (0.1 = 10%)
}

function calculateTokenExchangeRates(
supportedFiatCurrencies,
emoneyTokenExchangeRates,
fiatExchangeRates,
reducers
) {
return Object.entries(emoneyTokenExchangeRates).reduce(
(all, [denom, emoneyTokenToFiatExchangeRate]) => {
const [fiatCurrency, rate] = Object.entries(
emoneyTokenToFiatExchangeRate
)[0] // TODO dangerous if there will be more rates from the API directly
// precalculate the exchange rates for all denom currency pairs
supportedFiatCurrencies.forEach(supportedCurrency => {
all[reducers.denomLookup(denom)] =
all[reducers.denomLookup(denom)] || {}
all[reducers.denomLookup(denom)][supportedCurrency] =
supportedCurrency === fiatCurrency
? rate
: rate * fiatExchangeRates[fiatCurrency][supportedCurrency]
})
return all
},
{}
)
}

module.exports = {
...terraV3Reducers,
expectedRewardsPerToken,
fetchTokenExchangeRates,
totalBackedValueReducer
totalBackedValueReducer,
getTotalNetworkAnnualRewards,
calculateTokenExchangeRates
}
Loading

0 comments on commit 1a4cf11

Please sign in to comment.