From 66c02d5aaf20be06dd41b342259b2dc1a4062313 Mon Sep 17 00:00:00 2001 From: Fabian Date: Thu, 20 Feb 2020 00:36:30 -0500 Subject: [PATCH] release (#347) * Fabo/fix gas (#250) * fix gas estimate * linted * fixed test * do not keep data sources (#251) * track failing transactions in Sentry (#249) * correctly set the tx schema for a failing tx (#248) * Fabo/remove per block caching as not working (#247) * remove per block caching as not working * fix memoized results Co-authored-by: Ana G. <40721795+Bitcoinera@users.noreply.github.com> * delete perblockcachedatasource (#253) * Ana/fix balances in actionmodal (#255) * fix action modal available balance * include regen * use dictionary for denomlookup * use correct events for received txs (#257) * enable account creation for some networks (#252) * network update time metric added (#256) * network update time metric added * added missing dep Co-authored-by: Fabian * Fix proposal deposit (#261) * Remove denom handling from getDeposit() * Revert undesired change * delete package-lock.json * localtestnet config change (#265) * Ana/handle "address not from this network" error (#263) * add check address function for all queries * apply suggestions * Ana/add fiatvalue to balances query (e-Money) (#262) * preparation * more preparation * add fiatvalue field to balances query * fix get account info * apply suggestions * apply one last suggestion * suggestions+ Co-authored-by: Fabian * Ana/emoney fix expected returns with inflation and totalbacked (#243) * fix expected returns with inflation and supply * minor fixes. dictionary * query exchange rates from emoney api * fix infinite expected returns * convert api url to const * add eur value to totalbackedvalue. totalngm gains * add important comment * finish calculation * lint * catch errors with sentry Co-authored-by: Fabian * readd coin conversion (#268) * delete amount field (#274) * Fabo/increase gas again (#271) * icrease gas again * fixed test * Fabo/load all txs (even if more then first page in response) (#270) * load all txs (even if more then first page in response) * improved handling of txs * missing renaming * fixed paginated load * add pagination fix also to cosmosV0-source Co-authored-by: iambeone Co-authored-by: Ana G. <40721795+Bitcoinera@users.noreply.github.com> * fixing issue with multiple senders in one event (#273) * fixing issue with multiple senders in one event * Update lib/source/cosmosV2-source.js Co-authored-by: Fabian * Fabo/allow signing for terra + emoney (#267) * allow signing for terra * readd coin conversion * enable actions for terra * fix correct terra testnet url * comments and guards * enabled more txs for emoney and fixed broadcasting * added a catch for wrongly formatted broadcast urls * recover default field. change some network titles (#277) * Fabo/add network data to API (#278) * non desctructive introduction of better address prefix wording * added address creator to API * adjusted test * added ledger app to networks config * add icon property to schema (#281) * add icon property to schema * fix network schema validation Co-authored-by: Ana G. <40721795+Bitcoinera@users.noreply.github.com> * filter out validator specific txs (#279) * Ana/balances coinreducer good fix (#269) * balances coinreducer good fix * refactored fiat value logic Co-authored-by: Fabian * Create network_integration.md * Update network_integration.md * Update network_integration.md * Fabo/avoid 500 errors (#288) * avoid using the latest query * cleanup * Ana/filter validator tx cross network and add txvalue reducer (#285) * filter validators cross network * add value reducer. necessary for multi claim txs * add validator txs filter also for cosmosv0 source * filter and make array only claim rewards msg value * filter txs by whitelist * change length in multi claim reward reducer * add withdrawvalidators * replace dictionary for set * refactor transaction snippet. avoid repetition * Ana/emoney upgrade (mergeable) (#282) * update emoney api_url * fix denom. add default fiat currency * fix rpc endpoint * fix value (my bad) (#293) * fix value (my bad) * trigger another ci flow * erase space * set correct new chain id (#294) * restart API * restart API * fix pr alert (#297) * Fabo/298 tendermint reconnect (#300) * reconnect on tendermint disconnect * cleanup * comments * Update cosmos-node-subscription.js * Fabo/299 trigger a chain hangup error (#301) * trigger a chain hangup error * increase chain hangup time * Apply suggestions from code review * Fabo/store validator addresses (#296) * add validator addresses to db * linted * ignore in local dev * revert * fixed fetch * comment * refactored db into constructor * cleanup * add clearTimeout to avoid reconnection hell (#306) * add clearTimeout to avoid reconnection hell * removed console.log * Aleksei/luniedb replaced (#303) * add validator addresses to db * linted * ignore in local dev * revert * fixed fetch * comment * refactored db into constructor * cleanup * replaced luniedb * linted Co-authored-by: Fabian * disable reconnection logic * clear polling interval for tendermint connection * simple api fixes (#310) * Fabo/remove tendermint (#311) * remove tendermint * fixed empty blockHeight issue * small refactoring * catch on fetches to get logging * delay block updates * add retry logic * refactored getBlockByHeight * remove pm2 dep * validator profiles were returned as array (#312) * remove pr github action (#316) * fixing caching issue and more (#315) * fixing caching issue and more * clear chain hangup timeout * timeout fixed * Update lib/block-listeners/cosmos-node-subscription.js Co-authored-by: Jordan Bibla * added terra_mainnet to networks (#309) * added terra_mainnet to networks * errors fix reverted * Ana/add multidenom rewards. necessary for emoney (#308) * add multidenom rewards. necessary for emoney * add rewards to overview. improve code location * lint * add filter rewards for multidenom * important fix * another important fix * fix cannot read propery constructor of undefined (#318) * change terra mainnet title * pushing something to trigger new build and to restart the node * trying out nylira's node * WIP: Ana/More Terra fixes (#323) * fixing my mess * move all rewards logic to terra * clearly signal single denom rewards * Revert "WIP: Ana/More Terra fixes (#323)" (#325) This reverts commit 408186a3ef743ca51d513eb91c937f49960e7492. * catch inside block polling function (#327) * Fabo/disable writing validator addresses for now (#329) * disable writing validator addresses for now * linted * flushing http cache (#332) * Transaction abstraction schema (#333) * tx abstraction proposal using union * Use Coin type * Cleanup, TransactionV2 * Cleanup, not multisend tx * Unsupported tx (like multisend) don't have details * Fabo/switch to docker swarm mode (#330) * swtich to docker swarm mode * typo * Update .github/workflows/development.yml * Ana/more terra fixes (***THE COMEBACK***) (#324) * fixing my mess * move all rewards logic to terra * clearly signal single denom rewards * error structure has changed. need to look into it * also return denom for single denom rewards * manage errors properly * delete comments * Update lib/reducers/terraV3-reducers.js * loop through transaction messages * doing crazy stuff * rewrite the crazy bit Co-authored-by: Fabian * cosmosv0 was missing the retry logic (#334) * add back validator to db logic (#335) * path_prefix added to network data (#338) * path_prefix added to network data * path_prefix replaced to slug * tests fixed * remove regen (#337) Co-authored-by: Jordan Bibla * Fabo+Mario/transaction abstraction (#336) * draft for transaction abstraction * use lunie message types * Add supported tx types * WIP * Draft new reducers * Fix msg types * Need to resolve type for TransactionDetails union * debug resolver * lint * Fix * Cleanup * fix some union issues * Almost done * Small fixes * Add userTransactionAddedV2 * Add userTransactionAddedV2 to resolvers Co-authored-by: Mario Pino * emoney fixes for fiatvalue (#345) * emoney fixes for fiatvalue * refactor with coinreducer * speaking functions are your friends * refactor ugly nested code * lint * add denoms lookups for terra and emoney (#346) * Ana/add only tokens gas prices 2nd attempt (#344) * add terra and emoney gas price. terra reducer * delete fiatvalue from get balances in cosmos * add emoney reducer * hyper important emoney fixes * fix for emoney denoms * change gas price to micro units * add emoney denoms to denomlookup * transform to microunit also for terra tokens * return null for emoney gas prices * add harcoded gas prices * correct emoney hardcoded values * hardcoded terra gas prices. not working * update hardcoded values to working ones * delete unrelated changes to gas prices * apply suggestions except coinreducer * they call me mr coinreducer * change amount for price. add gas price reducer * change naming in gas price reducer * add error message Co-authored-by: Fabian Co-authored-by: Ana G. <40721795+Bitcoinera@users.noreply.github.com> Co-authored-by: Aleksey Rudometov Co-authored-by: Mario Pino Co-authored-by: Jordan Bibla --- data/networks.json | 34 ------ lib/message-types.js | 18 ++- lib/reducers/cosmosV0-reducers.js | 186 ++++++++++++++++++++++++++++-- lib/reducers/emoneyV0-reducers.js | 3 +- lib/reducers/regenV0-reducers.js | 5 - lib/reducers/terraV3-reducers.js | 29 ++++- lib/resolvers.js | 14 ++- lib/schema.js | 27 ++++- lib/source/cosmosV0-source.js | 21 +--- lib/source/cosmosV2-source.js | 11 ++ lib/source/emoneyV0-source.js | 59 ++++++++-- lib/source/regenV0-source.js | 36 ------ lib/source/terraV3-source.js | 52 +++++++++ 13 files changed, 373 insertions(+), 122 deletions(-) delete mode 100644 lib/reducers/regenV0-reducers.js delete mode 100644 lib/source/regenV0-source.js diff --git a/data/networks.json b/data/networks.json index 28e761d16c..5136cefc9b 100644 --- a/data/networks.json +++ b/data/networks.json @@ -67,40 +67,6 @@ "icon": "https://app.lunie.io/img/networks/cosmos-hub-mainnet.png", "slug": "cosmos-hub" }, - { - "id": "regen-testnet", - "title": "Regen Testnet", - "chain_id": "congo-1", - "rpc_url": "wss://regen-congo-1.lunie.io/websocket", - "api_url": "https://regen-congo-1.lunie.io", - "bech32_prefix": "xrn:", - "address_prefix": "xrn:", - "address_creator": "cosmos", - "ledger_app": "cosmos", - "source_class_name": "source/regenV0-source", - "block_listener_class_name": "block-listeners/cosmos-node-subscription", - "testnet": true, - "feature_session": true, - "feature_explore": true, - "feature_portfolio": true, - "feature_validators": true, - "feature_proposals": true, - "feature_activity": true, - "feature_explorer": true, - "action_send": true, - "action_claim_rewards": true, - "action_delegate": true, - "action_redelegate": true, - "action_undelegate": true, - "action_deposit": true, - "action_vote": true, - "action_proposal": true, - "default": false, - "stakingDenom": "TREE", - "enabled": true, - "icon": "https://app.lunie.io/img/networks/regen-testnet.png", - "slug": "regen-testnet" - }, { "id": "terra-mainnet", "title": "Terra", diff --git a/lib/message-types.js b/lib/message-types.js index 99bdea76b0..0265445da1 100644 --- a/lib/message-types.js +++ b/lib/message-types.js @@ -27,4 +27,20 @@ const cosmosWhitelistedMessageTypes = new Set([ `MsgMultiSend` ]) -module.exports = { cosmosMessageType, cosmosWhitelistedMessageTypes } +const lunieMessageTypes = { + SEND: `SendTx`, + STAKE: `StakeTx`, + RESTAKE: `RestakeTx`, + UNSTAKE: `UnstakeTx`, + VOTE: `VoteTx`, + DEPOSIT: `DepositTx`, + WITHDRAW_DELEGATION_REWARDS: `ClaimRewardsTx`, + SUBMIT_PROPOSAL: `SubmitProposalTx`, + UNKNOWN: `UnknownTx` +} + +module.exports = { + cosmosMessageType, + cosmosWhitelistedMessageTypes, + lunieMessageTypes +} diff --git a/lib/reducers/cosmosV0-reducers.js b/lib/reducers/cosmosV0-reducers.js index 7afd304477..d3f070aac7 100644 --- a/lib/reducers/cosmosV0-reducers.js +++ b/lib/reducers/cosmosV0-reducers.js @@ -1,6 +1,9 @@ const { uniqWith, sortBy, reverse } = require('lodash') const { cosmosMessageType } = require('../message-types') -const { cosmosWhitelistedMessageTypes } = require('../../lib/message-types') +const { + cosmosWhitelistedMessageTypes, + lunieMessageTypes +} = require('../../lib/message-types') const BigNumber = require('bignumber.js') const _ = require('lodash') const Sentry = require('@sentry/node') @@ -250,7 +253,16 @@ function denomLookup(denom) { uatom: 'ATOM', umuon: 'MUON', uluna: 'LUNA', - seed: 'TREE' + ukrw: 'KRW', + umnt: 'MNT', + usdr: 'SDR', + uusd: 'USD', + seed: 'TREE', + ungm: 'NGM', + eeur: 'eEUR', + echf: 'eCHF', + ejpy: 'eJPY', + eusd: 'eUSD' } return lookup[denom] ? lookup[denom] : denom.toUpperCase() } @@ -271,11 +283,8 @@ function coinReducer(coin) { } } -function balanceReducer(coin, fiatValue) { - return { - ...coin, - fiatValue - } +function balanceReducer(coin) { + return coin } function delegationReducer(delegation, validator) { @@ -406,6 +415,41 @@ function formatTransactionsReducer(txs, reducers) { return filteredTxs.map(tx => transactionReducer(tx, reducers)) } +function transactionReducerV2(transaction, reducers) { + // TODO check if this is anywhere not an array + let fees + if (Array.isArray(transaction.tx.value.fee.amount)) { + fees = transaction.tx.value.fee.amount.map(coinReducer) + } else { + fees = [coinReducer(transaction.tx.value.fee.amount)] + } + // We do display only the transactions we support in Lunie + const filteredMessages = transaction.tx.value.msg.filter( + ({ type }) => getMessageType(type) !== 'Unknown' + ) + const returnedMessages = filteredMessages.map(({ value, type }, index) => ({ + type: getMessageType(type), + hash: transaction.txhash, + height: transaction.height, + details: transactionDetailsReducer(getMessageType(type), value, reducers), + timestamp: transaction.timestamp, + memo: transaction.tx.value.memo, + fees, + success: transaction.logs ? transaction.logs[index].success : false + })) + return returnedMessages +} + +function transactionsReducerV2(txs, reducers) { + const duplicateFreeTxs = uniqWith(txs, (a, b) => a.txhash === b.txhash) + const sortedTxs = sortBy(duplicateFreeTxs, ['timestamp']) + const reversedTxs = reverse(sortedTxs) + // here we filter out all transactions related to validators + return reversedTxs.reduce((collection, transaction) => { + return collection.concat(transactionReducerV2(transaction, reducers)) + }, []) +} + // to be able to catch all validators from a multi-claim reward tx, we need to capture // more than just the first value message. function txMultiClaimRewardReducer(txMessages) { @@ -459,6 +503,130 @@ function transactionReducer(transaction, reducers) { } } +// map Cosmos SDK message types to Lunie message types +function getMessageType(type) { + // different networks use different prefixes for the transaction types like cosmos/MsgSend vs core/MsgSend in Terra + const transactionTypeSuffix = type.split('/')[1] + switch (transactionTypeSuffix) { + case 'MsgSend': + return lunieMessageTypes.SEND + case 'MsgDelegate': + return lunieMessageTypes.STAKE + case 'MsgBeginRedelegate': + return lunieMessageTypes.RESTAKE + case 'MsgUndelegate': + return lunieMessageTypes.UNSTAKE + case 'MsgWithdrawDelegationReward': + return lunieMessageTypes.WITHDRAW_DELEGATION_REWARDS + case 'MsgSubmitProposal': + return lunieMessageTypes.SUBMIT_PROPOSAL + case 'MsgVote': + return lunieMessageTypes.VOTE + case 'MsgDeposit': + return lunieMessageTypes.DEPOSIT + default: + return lunieMessageTypes.UNKNOWN + } +} + +// function to map cosmos messages to our details format +function transactionDetailsReducer(type, message, reducers) { + let details + switch (type) { + case lunieMessageTypes.SEND: + details = sendDetailsReducer(message, reducers) + break + case lunieMessageTypes.STAKE: + details = stakeDetailsReducer(message, reducers) + break + case lunieMessageTypes.RESTAKE: + details = restakeDetailsReducer(message, reducers) + break + case lunieMessageTypes.UNSTAKE: + details = unstakeDetailsReducer(message, reducers) + break + case lunieMessageTypes.WITHDRAW_DELEGATION_REWARDS: + details = claimRewardsDetailsReducer(message, reducers) + break + case lunieMessageTypes.SUBMIT_PROPOSAL: + details = submitProposalDetailsReducer(message, reducers) + break + case lunieMessageTypes.VOTE: + details = voteProposalDetailsReducer(message, reducers) + break + case lunieMessageTypes.DEPOSIT: + details = depositDetailsReducer(message, reducers) + break + default: + details = {} + } + + return { + type, + ...details + } +} + +function sendDetailsReducer(message, reducers) { + return { + to: [message.to_address], + amount: reducers.coinReducer(message.amount[0]) + } +} + +function stakeDetailsReducer(message, reducers) { + return { + to: [message.validator_address], + amount: reducers.coinReducer(message.amount) + } +} + +function restakeDetailsReducer(message, reducers) { + return { + from: [message.validator_src_address], + to: [message.validator_dst_address], + amount: reducers.coinReducer(message.amount) + } +} + +function unstakeDetailsReducer(message, reducers) { + return { + from: [message.validator_address], + amount: reducers.coinReducer(message.amount) + } +} + +function claimRewardsDetailsReducer(message, reducers) { + return { + from: [message.validator_address], + amount: reducers.coinReducer(message.amount) + } +} + +function submitProposalDetailsReducer(message, reducers) { + return { + proposalType: message.content.type, + proposalTitle: message.content.value.title, + proposalDescription: message.content.value.description, + initialDeposit: reducers.coinReducer(message.initial_deposit[0]) + } +} + +function voteProposalDetailsReducer(message) { + return { + proposalId: message.proposal_id, + voteOption: message.option + } +} + +// TO TEST! +function depositDetailsReducer(message, reducers) { + return { + proposalId: message.proposal_id, + amount: reducers.coinReducer(message.amount) + } +} + module.exports = { proposalReducer, governanceParameterReducer, @@ -476,6 +644,7 @@ module.exports = { calculateTokens, undelegationEndTimeReducer, formatTransactionsReducer, + transactionsReducerV2, atoms, proposalBeginTime, @@ -484,5 +653,6 @@ module.exports = { getTotalVotePercentage, getValidatorStatus, expectedRewardsPerToken, - getGroupByType + getGroupByType, + denomLookup } diff --git a/lib/reducers/emoneyV0-reducers.js b/lib/reducers/emoneyV0-reducers.js index cbfe6a31a6..6ddbc9c545 100644 --- a/lib/reducers/emoneyV0-reducers.js +++ b/lib/reducers/emoneyV0-reducers.js @@ -14,7 +14,7 @@ async function totalBackedValueReducer(totalBackedValue) { // fiat currency const fiatValue = exchangeRates[token] ? BigNumber(totalBackedValue.amount) - .div(100000000) + .div(1000000) .times(exchangeRates[token][ticker]) .toNumber() : null @@ -120,5 +120,6 @@ async function expectedRewardsPerToken( module.exports = { ...terraV3Reducers, expectedRewardsPerToken, + fetchTokenExchangeRates, totalBackedValueReducer } diff --git a/lib/reducers/regenV0-reducers.js b/lib/reducers/regenV0-reducers.js deleted file mode 100644 index f2df073e83..0000000000 --- a/lib/reducers/regenV0-reducers.js +++ /dev/null @@ -1,5 +0,0 @@ -const cosmosV0Reducers = require('./cosmosV0-reducers') - -module.exports = { - ...cosmosV0Reducers -} diff --git a/lib/reducers/terraV3-reducers.js b/lib/reducers/terraV3-reducers.js index cb5ff6cca6..bb89c4316b 100644 --- a/lib/reducers/terraV3-reducers.js +++ b/lib/reducers/terraV3-reducers.js @@ -1,5 +1,6 @@ const cosmosV2Reducers = require('./cosmosV2-reducers') -const { atoms } = cosmosV2Reducers +const BigNumber = require('bignumber.js') +const { atoms, denomLookup } = cosmosV2Reducers // Terra has a slightly different structure and needs its own undelegationEndTimeReducer function undelegationEndTimeReducer(transaction) { @@ -24,6 +25,31 @@ function undelegationEndTimeReducer(transaction) { } } +function gasPriceReducer(gasPrice) { + if (!gasPrice) { + throw new Error( + 'The token you are trying to request data for is not supported by Lunie.' + ) + } + + // we want to show only atoms as this is what users know + const denom = denomLookup(gasPrice.denom) + return { + denom: denom, + price: BigNumber(gasPrice.price).div(1000000) // Danger: this might not be the case for all future tokens + } +} + +function balanceReducer(coin, fiatValue, gasPrices) { + return { + ...coin, + fiatValue, + gasPrice: gasPriceReducer( + gasPrices.find(gasprice => denomLookup(gasprice.denom) === coin.denom) + ).price + } +} + function rewardReducer(rewards, validatorsDictionary) { const formattedRewards = rewards.map( reward => @@ -47,6 +73,7 @@ function rewardReducer(rewards, validatorsDictionary) { module.exports = { ...cosmosV2Reducers, + balanceReducer, rewardReducer, undelegationEndTimeReducer } diff --git a/lib/resolvers.js b/lib/resolvers.js index 1285a0a147..512e05eaec 100644 --- a/lib/resolvers.js +++ b/lib/resolvers.js @@ -316,7 +316,9 @@ const resolvers = { return overview }, transactions: (_, { networkId, address }, { dataSources }) => - remoteFetch(dataSources, networkId).getTransactions(address) + remoteFetch(dataSources, networkId).getTransactions(address), + transactionsV2: (_, { networkId, address }, { dataSources }) => + remoteFetch(dataSources, networkId).getTransactionsV2(address) }, Subscription: { blockAdded: { @@ -326,6 +328,10 @@ const resolvers = { subscribe: (_, { networkId, address }) => userTransactionAdded(networkId, address) }, + userTransactionAddedV2: { + subscribe: (_, { networkId, address }) => + userTransactionAdded(networkId, address) + }, event: { subscribe: withFilter( event, @@ -340,6 +346,12 @@ const resolvers = { } ) } + }, + // Resolve type for TransactionDetails union + TransactionDetails: { + __resolveType(obj) { + return obj.type + } } } diff --git a/lib/schema.js b/lib/schema.js index b2d936ca91..35e52040e9 100644 --- a/lib/schema.js +++ b/lib/schema.js @@ -29,6 +29,7 @@ const typeDefs = gql` denom: String! amount: String! fiatValue: String + gasPrice: String } type Proposal { @@ -160,8 +161,11 @@ const typeDefs = gql` SendTx | StakeTx | UnstakeTx + | RestakeTx | ClaimRewardsTx - | VoteProposalTx + | SubmitProposalTx + | VoteTx + | DepositTx type TransactionV2 { type: String! @@ -169,12 +173,14 @@ const typeDefs = gql` height: Int! details: TransactionDetails timestamp: String! + memo: String + fees: [Coin]! + success: Boolean! } type SendTx { amount: Coin! - to: String! - memo: String + to: [String]! } type StakeTx { @@ -182,6 +188,12 @@ const typeDefs = gql` to: [String]! } + type RestakeTx { + amount: Coin! + from: [String]! + to: [String]! + } + type UnstakeTx { amount: Coin! from: [String]! @@ -199,11 +211,16 @@ const typeDefs = gql` initialDeposit: Coin! } - type VoteProposalTx { + type VoteTx { proposalId: Int! voteOption: String! } + type DepositTx { + proposalId: Int! + amount: Coin! + } + type GovernanceParameters { depositDenom: String votingThreshold: Float @@ -247,6 +264,7 @@ const typeDefs = gql` type Subscription { blockAdded(networkId: String!): Block userTransactionAdded(networkId: String!, address: String!): Transaction + userTransactionAddedV2(networkId: String!, address: String!): TransactionV2 event(networkId: String!, eventType: String!, ressourceId: String): Event } @@ -292,6 +310,7 @@ const typeDefs = gql` operatorAddress: String ): [Reward] transactions(networkId: String!, address: String!): [Transaction] + transactionsV2(networkId: String!, address: String!): [TransactionV2] } ` diff --git a/lib/source/cosmosV0-source.js b/lib/source/cosmosV0-source.js index a013d5d407..39b67026cb 100644 --- a/lib/source/cosmosV0-source.js +++ b/lib/source/cosmosV0-source.js @@ -316,30 +316,13 @@ class CosmosV0API extends RESTDataSource { return this.reducers.blockReducer(this.networkId, block, transactions) } - async calculateFiatValues(balances, fiatCurrency) { - return Promise.all( - balances.map(balance => ({ - denom: this.reducers.coinReducer(balance).denom, - fiatValue: this.calculateFiatValue - ? this.calculateFiatValue(balance, fiatCurrency) - : null - })) - ) - } - - async getBalancesFromAddress(address, fiatCurrency = `EUR`) { + async getBalancesFromAddress(address) { this.checkAddress(address) const response = await this.query(`bank/balances/${address}`) let balances = response || [] const coins = balances.map(this.reducers.coinReducer) - // We calculate the fiatValue field for networks with multiple tokens - // For now, it is just e-Money - const fiatBalances = await this.calculateFiatValues(balances, fiatCurrency) return coins.map(coin => { - return this.reducers.balanceReducer( - coin, - fiatBalances.find(({ denom }) => denom === coin.denom).fiatValue - ) + return this.reducers.balanceReducer(coin) }) } diff --git a/lib/source/cosmosV2-source.js b/lib/source/cosmosV2-source.js index ac83a3982c..bee3345d3e 100644 --- a/lib/source/cosmosV2-source.js +++ b/lib/source/cosmosV2-source.js @@ -43,6 +43,17 @@ class CosmosV2API extends CosmosV0API { return this.reducers.formatTransactionsReducer(txs, this.reducers) } + async getTransactionsV2(address) { + this.checkAddress(address) + + const txs = await Promise.all([ + this.loadPaginatedTxs(`/txs?message.sender=${address}`), + this.loadPaginatedTxs(`/txs?transfer.recipient=${address}`) + ]).then(([senderTxs, recipientTxs]) => [].concat(senderTxs, recipientTxs)) + + return this.reducers.transactionsReducerV2(txs, this.reducers) + } + extractInvolvedAddresses(transaction) { // If the transaction has failed, it doesn't get tagged if (!Array.isArray(transaction.events)) return [] diff --git a/lib/source/emoneyV0-source.js b/lib/source/emoneyV0-source.js index b31e7e2981..7f7a88fdd4 100644 --- a/lib/source/emoneyV0-source.js +++ b/lib/source/emoneyV0-source.js @@ -3,9 +3,33 @@ const BigNumber = require('bignumber.js') const fetch = require('node-fetch') const apiURL = `https://api.exchangeratesapi.io/latest?` +const gasPrices = [ + { + denom: 'echf', + price: '0.400000' + }, + { + denom: 'eeur', + price: '0.400000' + }, + { + denom: 'ejpy', + price: '48.800000' + }, + { + denom: 'eusd', + price: '0.440000' + }, + { + denom: 'ungm', + price: '0.800000' + } +] + class EMoneyV0API extends TerraV3API { setReducers() { this.reducers = require('../reducers/emoneyV0-reducers') + this.gasPrices = gasPrices } // Here we query for the current inflation rates for all the backed tokens @@ -60,10 +84,7 @@ class EMoneyV0API extends TerraV3API { // To handle the NGM balance, first we convert to EUR value and then to the selected // fiat currency value if (denom === 'NGM') { - const eurValue = - BigNumber(balance.amount) - .div(100000000) - .toNumber() * 0.5 // 0.50€ is the price the NGM tokens will be first sold. Therefore, the official value until they reach an exchange + const eurValue = this.reducers.coinReducer(balance).amount * 0.5 // 0.50€ is the price the NGM tokens will be first sold. Therefore, the official value until they reach an exchange if (selectedFiatCurrency === `EUR`) { return parseFloat(eurValue) .toFixed(6) @@ -88,20 +109,20 @@ class EMoneyV0API extends TerraV3API { selectedFiatCurrency, denom ) - let totalFiatValue = 0 + let totalAsFiat = 0 // Here we check if the balance we are currently calculating the total fiat value from is // the same currency we want the fiat value to be displayed in. // In that case, we simply add it, don't need to convert it. if (denom !== selectedFiatCurrency) { - totalFiatValue = - BigNumber(balance.amount) - .div(100000000) - .toNumber() / rates[denom] + totalAsFiat = this.reducers.coinReducer(balance).amount / rates[denom] } else { - totalFiatValue = BigNumber(balance.amount) - .div(100000000) - .toNumber() + totalAsFiat = this.reducers.coinReducer(balance).amount } + // Now we do total value in the selected currency times the token fiat value + const totalFiatValue = await this.convertFiatValueToTokenFiatValue( + totalAsFiat, + denom + ) // Finally we get the proper currency sign to display const currencySign = this.getCurrencySign(selectedFiatCurrency) return parseFloat(totalFiatValue) @@ -119,6 +140,20 @@ class EMoneyV0API extends TerraV3API { .catch(error => console.error(error)) } + async convertFiatValueToTokenFiatValue(totalAsFiat, denom) { + const tokenExchangeRates = await this.reducers.fetchTokenExchangeRates() + const tokenExchangeRatesArray = Object.values(tokenExchangeRates) + const filterDenomFromExchangeRates = tokenExchangeRatesArray.filter( + rate => Object.keys(rate)[0] === denom + )[0] + const selectedFiatCurrencyExchangeRate = Object.values( + filterDenomFromExchangeRates + )[0] + return BigNumber(totalAsFiat) + .times(selectedFiatCurrencyExchangeRate) + .toNumber() + } + getCurrencySign(currency) { switch (currency) { case `EUR`: diff --git a/lib/source/regenV0-source.js b/lib/source/regenV0-source.js deleted file mode 100644 index 6aac4c292f..0000000000 --- a/lib/source/regenV0-source.js +++ /dev/null @@ -1,36 +0,0 @@ -const CosmosV0API = require('./cosmosV0-source') - -class RegenV0API extends CosmosV0API { - constructor(network) { - super(network) - - this.delegatorBech32Prefix = `xrn:` - this.validatorConsensusBech32Prefix = `xrn:valcons` - } - setReducers() { - this.reducers = require('../reducers/regenV0-reducers') - } - - async getTransactionsByHeight(height) { - const { txs } = await this.get(`txs?tx.height=${height}`) - return Array.isArray(txs) - ? txs.map(transaction => - this.reducers.transactionReducer(transaction, this.reducers) - ) - : [] - } - - async getTransactions(address) { - this.checkAddress(address) - const pagination = `&limit=${1000000000}` - - const txs = await Promise.all([ - this.get(`/txs?sender=${address}${pagination}`).then(({ txs }) => txs), - this.get(`/txs?recipient=${address}${pagination}`).then(({ txs }) => txs) - ]).then(([senderTxs, recipientTxs]) => [].concat(senderTxs, recipientTxs)) - - return this.reducers.formatTransactionsReducer(txs, this.reducers) - } -} - -module.exports = RegenV0API diff --git a/lib/source/terraV3-source.js b/lib/source/terraV3-source.js index 924838a439..645f405d15 100644 --- a/lib/source/terraV3-source.js +++ b/lib/source/terraV3-source.js @@ -6,9 +6,33 @@ const { pubkeyToAddress } = require('../tools') // Terra is provisioning this amount manually https://medium.com/terra-money/project-santa-community-initiative-b8ab6c4d79be const annualProvision = '21700000000000' // 21.7 million in uluna +const gasPrices = [ + { + denom: 'ukrw', + price: '0.091000' + }, + { + denom: 'uluna', + price: '0.001000' + }, + { + denom: 'umnt', + price: '0.091000' + }, + { + denom: 'usdr', + price: '0.091000' + }, + { + denom: 'uusd', + price: '0.091000' + } +] + class TerraV3API extends CosmosV2API { setReducers() { this.reducers = require('../reducers/terraV3-reducers') + this.gasPrices = gasPrices } async getAllValidators(height) { @@ -78,6 +102,34 @@ class TerraV3API extends CosmosV2API { ) return this.reducers.rewardReducer(rewards, validatorsDictionary) } + + async calculateFiatValues(balances, fiatCurrency) { + return Promise.all( + balances.map(balance => ({ + denom: this.reducers.coinReducer(balance).denom, + fiatValue: this.calculateFiatValue + ? this.calculateFiatValue(balance, fiatCurrency) + : null + })) + ) + } + + async getBalancesFromAddress(address, fiatCurrency = `EUR`) { + this.checkAddress(address) + const response = await this.query(`bank/balances/${address}`) + let balances = response || [] + const coins = balances.map(this.reducers.coinReducer) + // We calculate the fiatValue field for networks with multiple tokens + // For now, it is just e-Money (probably also Terra) + const fiatBalances = await this.calculateFiatValues(balances, fiatCurrency) + return coins.map(coin => { + return this.reducers.balanceReducer( + coin, + fiatBalances.find(({ denom }) => denom === coin.denom).fiatValue, + this.gasPrices + ) + }) + } } module.exports = TerraV3API