From aaf1f378ed8f39b7967daabc37d082f9649862ae Mon Sep 17 00:00:00 2001 From: Fabian Date: Tue, 31 Mar 2020 10:35:13 -0500 Subject: [PATCH] release (#544) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 * fix rewards denoms (#351) * updating image on deploy (#352) * fix my mess once more (#353) * Ana/add gas prices to other networks (#350) * add gasprices to cosmos * format gas prices to three decimals * Apply suggestions from code review * Update lib/reducers/cosmosV0-reducers.js Co-authored-by: Fabian Co-authored-by: Jordan Bibla * added a tx success push, fallback (#354) * fix cosmos gas price (#355) * fix terra for new tmbalance (#358) * Fabo/new emoney rewards (#357) * intent to fix the emoney rewards * intent to fix emoney rewards * simplified code * comments * hack to fix reduce function * eligable -> eligible * correct reducer fix Co-authored-by: Ana G. <40721795+Bitcoinera@users.noreply.github.com> Co-authored-by: Jordan Bibla * Aleksei/prevent constant db calls (#304) * add validator addresses to db * linted * ignore in local dev * revert * fixed fetch * comment * refactored db into constructor * cleanup * prevent constant db interaction * stored object structure changed * remove nesting in validators * filter validators list Co-authored-by: Fabian * limit txs pages load by two pages per request (#314) * limit txs pages load by two pages per request * delete block from loadpaginatedtxs * small fixes * Update lib/source/cosmosV2-source.js * linted Co-authored-by: Ana G. <40721795+Bitcoinera@users.noreply.github.com> Co-authored-by: Fabian * linted * linted * Fabo/Use figment nodes (#362) * use api keys * add env variables for nodes * hard code api keys (#365) * fix ngm fiatvalue (#361) * hardcoded urls fix (#366) * WIP: Improve TransactionV2 implementation (#349) * Add from field to SendTx type * add amount to claim rewards transactions * convert to units in string coin reducer * fix typo * add multidenom string coinreducer for claim amount * Add UnknownTx to schema * Add BlockV2 type which returns TransactionV2 txs * Add blockV2 query that returns TransactionV2 txs * kill handling claim rewards amount * Update lib/reducers/cosmosV0-reducers.js Co-Authored-By: Fabian * Update lib/reducers/cosmosV0-reducers.js Co-Authored-By: Fabian * Cleanup * lint * Support claim rewards from multiple validators * Fix, cleanup Co-authored-by: Ana G. <40721795+Bitcoinera@users.noreply.github.com> Co-authored-by: Fabian * Aleksei/fix db insert (#367) * fixed insert function to allow empty schema * Aleksei/statistics in the api (#364) * collecting statistics in the API * small fixes * fixes * changing address to key in clearOverviewedAddresses Co-authored-by: Aleksey Rudometov * add pageNumber to schema (#370) * add pageNumber to schema * file wasn't saved * trigger ci * added pagination to tx v2 api (#372) * Together with 3584: Ana/change fiatvalue to object (#360) * change fiatvalue to object * handle when selected currency is eur * include ngm fiatvalue fix * Ana/amount in claim rewards in transactions v2 (#373) * bring amount in claim rewards back to life * change to regex * simplify * make the regex understandable * Ana/add powered to networks (#377) * add powered by * more logical powered * add provider address for avatar * fix powere validation * Fabo/add network-type for selecting addrss and signing (#378) * add network-type for selecting addrss and signing * adjust according to new network_type param * add network type to network schema Co-authored-by: Ana G. <40721795+Bitcoinera@users.noreply.github.com> * fix staking denom (#379) * fix terra balances and overview (#380) * Fabo/allow to query experimental networks (#382) * all to query experimental networks * fix old small typo Co-authored-by: Ana G. <40721795+Bitcoinera@users.noreply.github.com> * First steps to integrate Polkadot (#376) * Add polkadot-testnet in networks.js * Install polkadot-api, polkadot-node-sub. draft * lint * lint * lint * add polkadotV0 source * add address creator * Update data/networks.js Co-Authored-By: Jordan Bibla * Update data/networks.js Co-Authored-By: Jordan Bibla * blocks, events * Cleanup * polling instead subscription * husky * updateDBValidatorProfiles * no wait for block data fetching, kind of stable * Add reducers file * block subscription works! * Cleanup, fix memory leak * lint, node * comment * Handle polkadot chain reorgs * Cleanup * Optimization, cleanup * Optimization * fixes, validators query working, cleanup * comment * lint * fix block time * handle polkadot chain hangups * cleanup * validator reducer * lint * wip * calculate and include a bunch of validator fields * add bech32_prefix address_prefix to networks.js * add 1 space so we dont break tests * remove chain reorg handling, more stable Co-authored-by: Ana G. <40721795+Bitcoinera@users.noreply.github.com> Co-authored-by: Fabian Co-authored-by: Jordan Bibla * transactions loading time reduced (#383) * transactions loading time reduced * increased page number * add loki to docker-compose (#385) * add network type (#386) * removed livepeer from running in API (#390) * set polkadot to disabled (#392) * Ana/add totalstake-fiatvalue to Overview (#384) * add totalstake fiat value to overview * fix amount in totalstake fiatvalue * make new code more readable * Update lib/reducers/cosmosV0-reducers.js * refactor unit conversion Co-authored-by: Mario Pino * disable polkadot (#395) Co-authored-by: Fabian * Fabo/terra returns (#389) * better error logging * add result selector to query * split emoney getAllValidators from Terra * add expected returns querying to terra * filter out empty returns * remove not used code * missing return * limit decimals * fix not found in terra testnet * temporary hacks * Revert "temporary hacks" This reverts commit 88d0918af70489422d6d5d84909df1186a23fa1c. * Revert "fix not found in terra testnet" This reverts commit 19a4eca6eb4a9eb2050b368b270d4a39847e016a. * add terra testnet api * switch to show all decimals Co-authored-by: Ana G. <40721795+Bitcoinera@users.noreply.github.com> * fix all fiat values to 2 decimals (#399) * Ana/correct terra denoms (#398) * correct terra denoms * variable renaming Co-authored-by: Fabian * Ana/add fiatvalue in rewards (#396) * add fiatvalue to rewards * add fiatcurrency to rewards query * handle unsupported fiat currencies * apply suggestions * delete never used delegations parameter (#404) * fix terra getrewards and gas prices (#409) * reactivate kusama (#411) * Ana/fix repeated claim rewards transactions in transaction abstraction (#400) * fix terra repeated claim rewards transactions * much better fix * add claim rewards messages aggregator * try to apply suggestion * also not working * working 🎉 * change name and add comment * improved implementation by aggregating the claim messags correctly Co-authored-by: Fabian Weber * disable polkadot once more for release (#412) * readd memory limit (#413) * Use polling instead subscription in Kusama (#406) * uncomment polkadot * bug fixes * pollForNewBlock * mod getBlockHeight * add again commented api disconnect to not forget * enqueueAndPublishBlockAdded * re-subscribe on error * stringify error * stringify errors * api.isReady * Add delay to newBlockHandler * Ana/add balances to kusama (#405) * rudimentary balance * add some comment * Ana/switch polkadot to rest calls (#408) * add rewards and overview functions. not working * poll instead of subscribe to blocks * switch over to http provider * fix lint errors * use httpprovider * getting last block hash * get blockhash and header. but no height * back to normal. use mario node subscription * successfully get block height polling with http * get block hash from http. use polling * uncomment all other networks * pass the store to source classes * create the api only once * comment api.disconnect() * added polling fix and quick querying * fixed block height query * clean up * comment * cleanup and optimization Co-authored-by: Fabian Weber Co-authored-by: mariopino * remove unused dependency Co-authored-by: Bitcoinera Co-authored-by: Ana G <40721795+Bitcoinera@users.noreply.github.com> Co-authored-by: Fabian Weber * deactivate polkadot * trigger deploy * trigger CI * swtich to newer caddy version * activate polkadot again * deactivate again * Proposal to enable Kusama network (#424) * working state * cleanup * getBlockHeight() * update polkadot-api (#423) * fixing node_exporter call in Caddyfile (#418) * fixing send amount in statistics (#419) * fixing send amount in statistics * denom fixed * fix validator as selected fiat bug (#415) * Ana/correct terra denoms in activity (#425) * correct fix terra denoms in activity * delete correct terra denom as not needed * Ana/fix amount null in claim rewards (#416) * fix amount null in claim rewards * small refactor * apply suggestion * add release script to api (#426) * Add self stake to validators query (#433) * add self stake * Update lib/reducers/polkadotV0-reducers.js Co-Authored-By: Ana G. <40721795+Bitcoinera@users.noreply.github.com> * lint Co-authored-by: Ana G. <40721795+Bitcoinera@users.noreply.github.com> Co-authored-by: Bitcoinera * fix emoney balances denoms (#436) * [Polkadot] Add delegations query (#435) * first step, simplified query is working * lint * Get validator info from val dictionary * cleanup, fix comission * fix * faster solution * remove types we dont need in store * @Aleksei suggestions * fix * fix * simplify as @imbeone suggested * simplify, thanks @bitcoinera! * re adding array check * delegationReducer * fix * Ana/update polkadot balances (#441) * update polkadot balances * structs are strange * change comment * disable kusama * disable kusama * Ana/427 polkadot single validator query (#440) * save validators with operatoraddress as key * add check to wait to fetch validators * Update lib/resolvers.js Co-Authored-By: Fabian * Update lib/resolvers.js Co-Authored-By: Fabian * lint * fix delegations Co-authored-by: Fabian * Add denom decimal places to networks.js (#434) * lint * add decimals places, refactor POLKADOT_CONVERSION * add to schema * add to tests * refactor with @faboweb suggestions * fix * fix * fix * cleanup * apply suggestions * fix balances * add factor properly to network Co-authored-by: Bitcoinera * fix totalstake fiatvalue only returning euro (#442) * Fix commission for validators in Polkadot network (#447) * fix commission * comment * Fix expectedReturns for validators in Polkadot network (#446) * fix expectedReturns * change -- for null in getrewards and returns Co-authored-by: Bitcoinera * Ana/emoney validators load optimization (#430) * just for testing. hang up on validatorssets latest * fix emoney validators load * resolve conflict * remove experimental line * linted * Fabo/polkadot overview (#450) * add first steps towards overview * correct total * fixed total * fix getaccountinfo is not a funciton * delete hardcoded node rpc url * endpoint back to normal Co-authored-by: Bitcoinera * change polkadot node back to paritys one (#453) * Bump acorn from 5.7.3 to 5.7.4 (#454) Bumps [acorn](https://github.com/acornjs/acorn) from 5.7.3 to 5.7.4. - [Release notes](https://github.com/acornjs/acorn/releases) - [Commits](https://github.com/acornjs/acorn/compare/5.7.3...5.7.4) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Fabo/improve delegations (#455) * improve delegations * removed timer * add hack for accounts with no nominations Co-authored-by: Bitcoinera * update polkadot api to latest (#456) * updated minimist (#457) * add empty getundelegations for polkadot (#458) * Update polkadot api to v1.7.1 (#465) * Ana/fix calculatefiatvalue when fiatcurrency not set (#462) * fix calculatefiatvalue when fiatcurrency not set * improve fix and comment * linted * Upgrade @polkadot/api to v1.8.0-beta.1 (#471) * Add intention validators in Polkadot network (#468) * Add timer to getAllValidators() * Fetch intention addresses for current session * wip * Add validators * working! getAllValidators exec time less than 10s * fix status * Cleanup * fix free balance (#474) * Fix delegations query in Polkadot network (#475) * fetch delegations from stored valid. staking info * Simplify * Cleanup * tx type in v2 subscriptions changed to TransactionV2 (#476) * Ana/add new release script copying fe (#479) * add new release script copying fe * add node executor to circleci * add aliases for circleci * missed one alias * change uluna gas price to recommended one (#481) * fixing claim rewards pubsub publishing (#480) * fixing claim rewards pubsub publishing * only get stakingDenom once Co-authored-by: Fabian Weber * Fabo/fix failed txs parsing (#486) * publish v2 txs and fix failed txs parsing * linted * Fabo/add logs to txs v2 (#487) * add logs to txs v2 * better logic * michiel/move yarn test to separate step for circleci (#482) * migrate test.yml github workflow to circleci config.yml fix executor from web to node * remove test.yml workflow file * refactor address extraction into reducers (#488) * add polkadot prefix (#489) * add polkadot prefix * change address prefix to be a number * Fabo/broadcast polkadot txs (#461) * first steps to broadcast polkadot txs * remove package-lock * fixed api init * remove debugger * working broadcasting * working * ignore polkadot in tests * Update lib/controller/transaction/index.js Co-Authored-By: Jordan Bibla Co-authored-by: Jordan Bibla * Fabo/wait for data ready (#497) * allow to wait for data to be ready (cherry picked from commit 744d9b3b445286a9637fdadbeb5c473165cec58e) * wait for data to be ready (cherry picked from commit b6d665fd88ae22e5e3753249f27730eb12faebcb) * keep store in cosmos source (cherry picked from commit a6bb9f023eb56fb57d9a0f3a3ae12c997f6d04e3) * Update lib/resolvers.js * adds key to identify and sort txs (#492) * improve blockHandler logic (#498) (cherry picked from commit b67fab47adbf5a19caf99e17a9395e62419e8dad) * Fabo/enable terra governance (#501) * enable terra governance * also enable proposals in terra testnet * Ana/send all claimed rewards to fe (#493) * send all claimed rewards to fe * refactor reward coin reducer * Fabo/allow single network run (#495) * allow running a single network * readme * apply fix in networks * Update lib/apollo.js Co-authored-by: Bitcoinera * Ana/refactor network capabilities (#502) * refactor network capabilities * refactor to have just a dictionary * fix terra testnet. deleted accidentally testnet Co-authored-by: Fabian * Fabo/fix emoney reward precision (#504) * fix emoney rewards precision * comment * remove polkadot log spamming * add logging for failing tx parsing * more kusama log removal * Fabo/improve emoney loading (#494) * 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 * fix transaction log parsing * better debugging * prevent transactionReducerV2 from returning undefined (#508) * prevent transactionReducerV2 from returning undefined * Update lib/reducers/cosmosV0-reducers.js Co-Authored-By: Ana G. <40721795+Bitcoinera@users.noreply.github.com> * linting fix Co-authored-by: Ana G. <40721795+Bitcoinera@users.noreply.github.com> * fix one more log parsing issue * WIP Ana/make estimate a query (#509) * first attempt for estimate * fix estimate schema * lint * Polkadot send transaction extraction (#500) * tx logic draft * fix lint * wip * lint * working for send tx type * should work publishing send tx! * correct data is being passed to publishers * cleanup * working with extrinsics * implement coin reducer * Update lib/reducers/polkadotV0-reducers.js Co-Authored-By: Fabian * Update lib/reducers/polkadotV0-reducers.js Co-Authored-By: Fabian Co-authored-by: Fabian * Ana/add emoney mainnet (#511) * first preparations * Update data/networks.js Co-Authored-By: Fabian * Update data/networks.js Co-Authored-By: Fabian * add correct chainid * add validators poller for release * check emoney mainnet validators recursively Co-authored-by: Fabian * fix no iterable for claimrewards amounts (#515) * emoney mainnet is mainnet (#517) * remove emoney release hack (#520) * fix emoney mainnet expected returns (#522) * useless console.log removed (#519) * update emoney ngm gasprice (#525) * Michiel/make clear separation between v0 and v2 reducers (#530) * Replace transactionReducer with v2 for pollTransactionSuccess * Replace transactionReducer with v2 for pollTransactionSuccess * Fix structure * Make clear seperation between v0 and v2 reducers * Fix problem publishing transaction * Fix pollTransactionSuccess * Fix pollTransactionSuccess * Ana/fix claim rewards denom for terra and emoney (#534) * fix claim rewards denom for terra and emoney * fix again * Ana/fix expected returns cosmos and emoney (#536) * fix expected returns for cosmos and emoney * add missing property in type validator * delete delegatorshares from type validator * Ana/add gas estimates query (#503) * add network fees query * fix schema * refactor using networkid with hyphens * return only estimate for a transaction type * add gas estimates to network object * remove network fees from queries * revert last two commits manually * add default to network gas estimates * apply suggestion * michiel/remove reducer v0 (#535) * Remove reducer v0 * Update cosmosV0-source.js * linted Co-authored-by: Fabian * comment instructions on github templates (#539) * Ana/fix gasestimate query and raise terra default gas estimate (#538) * fix networkfees query * raise terra default gas estimate * Michiel/add akash portfolio (#541) * first steps * Integrate validators feature for akashv0 * Simplify extending Cosmos logic * Remove unused imports * Uncomment networks * Enable portfolio for Akash * Commnet livepeer mainnet network * Commnet livepeer mainnet network * fix validators expected returns * apply code review * use proper reducers * add gas prices * fix totalstake and delegation in general * fix api_url * correct staking denom to cosmossdk default for now * add also default stake gas price Co-authored-by: Bitcoinera * Michiel/add Akash validators (#540) * first steps * Integrate validators feature for akashv0 * Simplify extending Cosmos logic * Remove unused imports * Uncomment networks * Commnet livepeer mainnet network * fix validators expected returns * apply code review * Fix version transactionsByHeight Co-authored-by: michielmulders Co-authored-by: Ana G. <40721795+Bitcoinera@users.noreply.github.com> Co-authored-by: iambeone Co-authored-by: Mario Pino Co-authored-by: Jordan Bibla Co-authored-by: Bitcoinera Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Michiel Mulders --- .github/ISSUE_TEMPLATE/bug_report.md | 32 +- .github/ISSUE_TEMPLATE/feature_request.md | 8 +- data/network-capabilities.js | 17 + data/network-fees.js | 43 +++ data/networks.js | 23 +- lib/controller/transaction/index.js | 47 +-- lib/message-types.js | 31 -- lib/reducers/akashV0-reducers.js | 29 ++ lib/reducers/cosmosV0-reducers.js | 388 +--------------------- lib/reducers/cosmosV2-reducers.js | 266 ++++++++++++++- lib/resolvers.js | 11 +- lib/schema.js | 10 +- lib/source/akashV0-source.js | 48 +++ lib/source/cosmosV0-source.js | 34 +- 14 files changed, 515 insertions(+), 472 deletions(-) create mode 100644 data/network-fees.js create mode 100644 lib/reducers/akashV0-reducers.js create mode 100644 lib/source/akashV0-source.js diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index dd84ea7824..7df37298c2 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -8,31 +8,31 @@ assignees: '' --- **Describe the bug** -A clear and concise description of what the bug is. + **To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error + + + + + **Expected behavior** -A clear and concise description of what you expected to happen. + **Screenshots** -If applicable, add screenshots to help explain your problem. + **Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] + - OS: + - Browser: + - Version: **Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] + - Device: + - OS: + - Browser: + - Version: **Additional context** -Add any other context about the problem here. + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index bbcbbe7d61..a6f653e0b8 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -8,13 +8,13 @@ assignees: '' --- **Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + **Describe the solution you'd like** -A clear and concise description of what you want to happen. + **Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. + **Additional context** -Add any other context or screenshots about the feature request here. + diff --git a/data/network-capabilities.js b/data/network-capabilities.js index 1d29768056..e874191806 100644 --- a/data/network-capabilities.js +++ b/data/network-capabilities.js @@ -117,6 +117,23 @@ const getNetworkCapabilities = { action_deposit: false, action_vote: false, action_proposal: false + }, + "akash-testnet": { + feature_session: true, + feature_explore: true, + feature_portfolio: true, + feature_validators: true, + feature_proposals: false, + feature_activity: false, + feature_explorer: false, + action_send: false, + action_claim_rewards: false, + action_delegate: false, + action_redelegate: false, + action_undelegate: false, + action_deposit: false, + action_vote: false, + action_proposal: false } } diff --git a/data/network-fees.js b/data/network-fees.js new file mode 100644 index 0000000000..38254617c2 --- /dev/null +++ b/data/network-fees.js @@ -0,0 +1,43 @@ +const { UserInputError } = require('apollo-server') + +const transactionTypesSet = new Set(['SendTx', 'StakeTx', 'UnstakeTx', 'RestakeTx', 'ClaimRewardsTx', 'SubmitProposalTx', 'VoteTx', 'DepositTx', 'UnknownTx']) + +const getNetworkTransactionGasEstimates = (networkId, transactionType) => { + if (transactionType && !transactionTypesSet.has(transactionType)) { + throw new UserInputError(`Unrecognized transaction type. Valid transaction types are 'SendTx', 'StakeTx', 'UnstakeTx', 'RestakeTx', 'ClaimRewardsTx', 'SubmitProposalTx', 'VoteTx', 'DepositTx' and 'UnknownTx'`) + } + const networkGasEstimates = networkGasEstimatesDictionary[networkId] + if (!networkGasEstimates) { + throw new UserInputError(`Unrecognized network. Currently only Cosmos, Terra and e-Money do have a network fees set`) + } + return transactionType && networkGasEstimates[`${transactionType}`] ? networkGasEstimates[`${transactionType}`] : networkGasEstimates.default +} + +const terraGasEstimates = { + default: 300000 +} + +const cosmosGasEstimates = { + default: 550000 +} + +const emoneyGasEstimates = { + default: 200000, + ClaimRewardsTx: 550000 +} + +const akashGasEstimates = { + default: 200000 +} + +const networkGasEstimatesDictionary = { + "cosmos-hub-mainnet": cosmosGasEstimates, + "cosmos-hub-testnet": cosmosGasEstimates, + "terra-mainnet": terraGasEstimates, + "terra-testnet": terraGasEstimates, + "emoney-mainnet": emoneyGasEstimates, + "emoney-testnet": emoneyGasEstimates, + "akash-testnet": akashGasEstimates +} + +module.exports = {getNetworkTransactionGasEstimates} \ No newline at end of file diff --git a/data/networks.js b/data/networks.js index 260803c280..040b9f5c8e 100644 --- a/data/networks.js +++ b/data/networks.js @@ -168,7 +168,28 @@ module.exports = [ enabled: false, icon: 'https://app.lunie.io/img/networks/polkadot-testnet.png', slug: 'kusama' - } + }, + { + id: 'akash-testnet', + title: 'Akash Testnet', + chain_id: 'devnet', + api_url: 'http://95.179.133.80:8080', + rpc_url: 'wss://95.179.133.80:26657/websocket', + bech32_prefix: 'akash', + address_prefix: 'akash', + address_creator: 'cosmos', + ledger_app: 'cosmos', + network_type: 'cosmos', + source_class_name: 'source/akashV0-source', + block_listener_class_name: 'block-listeners/cosmos-node-subscription', + testnet: true, + ...getNetworkCapabilities[`akash-testnet`], + default: false, + stakingDenom: 'STAKE', + enabled: false, + icon: 'https://app.lunie.io/img/networks/akash-testnet.png', + slug: 'akash-testnet' + }, // { // id: 'livepeer-mainnet', // title: 'Livepeer', diff --git a/lib/controller/transaction/index.js b/lib/controller/transaction/index.js index 750467172c..d065532f1e 100644 --- a/lib/controller/transaction/index.js +++ b/lib/controller/transaction/index.js @@ -1,8 +1,8 @@ // const { getMessage } = require('./messageConstructor') const { networkMap } = require('../../networks') const Sentry = require('@sentry/node') -const { publishUserTransactionAdded } = require('../../subscriptions') -const reducers = require('../../reducers/cosmosV0-reducers') // TODO the whole transaction service only works for cosmos rn +const { publishUserTransactionAddedV2 } = require('../../subscriptions') +const reducers = require('../../reducers/cosmosV2-reducers') // TODO the whole transaction service only works for cosmos rn const { prestore, storePrestored, @@ -271,31 +271,40 @@ async function pollTransactionSuccess( // publishUserTransactionAdded is also done in the block subscription // but also here as a fallback // TODO the client might now update twice as it receives the success twice, could be fine though - const transaction = reducers.transactionReducer(res, reducers) + const transactions = reducers.transactionReducerV2(res, reducers) // store in db storePrestored(hash) // we need to call - publishUserTransactionAdded(networkId, senderAddress, transaction) + transactions.forEach(transaction => + publishUserTransactionAddedV2(networkId, senderAddress, transaction) + ) } catch (error) { console.error('TX failed:', hash, error) - let transaction + + let transactions if (res.tx) { - transaction = reducers.transactionReducer(res, reducers) + transactions = reducers.transactionReducerV2(res, reducers) } else { - // on timeout we don't get a transaction back - transaction = { - type: '', - hash, - height: -1, - group: '', - timestamp: '', - signature: '', - value: '', - success: false, - log: error.message - } + // on timeout we don't get a transactionV2 back + transactions = [ + { + type: '', + hash, + key: '', + height: -1, + details: {}, + timestamp: '', + memo: '', + success: false, + log: error.message + } + ] } - publishUserTransactionAdded(networkId, senderAddress, transaction) + + transactions.forEach(transaction => + publishUserTransactionAddedV2(networkId, senderAddress, transaction) + ) + Sentry.withScope(scope => { scope.setExtra('api_url', url) scope.setExtra('hash', hash) diff --git a/lib/message-types.js b/lib/message-types.js index 05f16e52e7..0716a7f6a2 100644 --- a/lib/message-types.js +++ b/lib/message-types.js @@ -1,32 +1,3 @@ -const cosmosMessageType = { - SEND: 'cosmos-sdk/MsgSend', - CREATE_VALIDATOR: 'cosmos-sdk/MsgCreateValidator', - EDIT_VALIDATOR: 'cosmos-sdk/MsgEditValidator', - DELEGATE: 'cosmos-sdk/MsgDelegate', - UNDELEGATE: 'cosmos-sdk/MsgUndelegate', - BEGIN_REDELEGATE: 'cosmos-sdk/MsgBeginRedelegate', - UNJAIL: 'cosmos-sdk/MsgUnjail', - SUBMIT_PROPOSAL: 'cosmos-sdk/MsgSubmitProposal', - DEPOSIT: 'cosmos-sdk/MsgDeposit', - VOTE: 'cosmos-sdk/MsgVote', - SET_WITHDRAW_ADDRESS: 'cosmos-sdk/MsgSetWithdrawAddress', - WITHDRAW_DELEGATION_REWARD: 'cosmos-sdk/MsgWithdrawDelegationReward', - WITHDRAW_VALIDATOR_COMMISSION: 'cosmos-sdk/MsgWithdrawValidatorCommission', - MULTI_SEND: 'cosmos-sdk/MsgMultiSend' -} - -const cosmosWhitelistedMessageTypes = new Set([ - `MsgSend`, - `MsgDelegate`, - `MsgBeginRedelegate`, - `MsgUndelegate`, - `MsgVote`, - `MsgDeposit`, - `MsgWithdrawDelegationReward`, - `MsgSubmitProposal`, - `MsgMultiSend` -]) - const lunieMessageTypes = { SEND: `SendTx`, STAKE: `StakeTx`, @@ -40,7 +11,5 @@ const lunieMessageTypes = { } module.exports = { - cosmosMessageType, - cosmosWhitelistedMessageTypes, lunieMessageTypes } diff --git a/lib/reducers/akashV0-reducers.js b/lib/reducers/akashV0-reducers.js new file mode 100644 index 0000000000..272ea87343 --- /dev/null +++ b/lib/reducers/akashV0-reducers.js @@ -0,0 +1,29 @@ +const terraV3Reducers = require('./terraV3-reducers') + +function blockReducer(networkId, block, transactions) { + return { + networkId, + height: block.block.header.height, + chainId: block.block.header.chain_id, + hash: block.block_id.hash, + time: block.block.header.time, + transactions, + proposer_address: block.block.header.proposer_address + } +} + +function delegationReducer(delegation, validator) { + const delegationCoin = terraV3Reducers.coinReducer(delegation.balance) + return { + validatorAddress: delegation.validator_address, + delegatorAddress: delegation.delegator_address, + validator, + amount: delegationCoin.amount + } +} + +module.exports = { + ...terraV3Reducers, + blockReducer, + delegationReducer +} diff --git a/lib/reducers/cosmosV0-reducers.js b/lib/reducers/cosmosV0-reducers.js index 238a10ca3d..93fd9d025f 100644 --- a/lib/reducers/cosmosV0-reducers.js +++ b/lib/reducers/cosmosV0-reducers.js @@ -1,12 +1,10 @@ -const { uniqWith, sortBy, reverse } = require('lodash') -const { cosmosMessageType } = require('../message-types') -const { - cosmosWhitelistedMessageTypes, - lunieMessageTypes -} = require('../../lib/message-types') +const { flatten } = require('lodash') const BigNumber = require('bignumber.js') -const _ = require('lodash') -const Sentry = require('@sentry/node') + +/** + * Modify the following reducers with care as they are used for ./cosmosV2-reducer.js as well + * [proposalBeginTime, proposalEndTime, getDeposit, tallyReducer, atoms, getValidatorStatus, coinReducer] + */ function proposalBeginTime(proposal) { switch (proposal.proposal_status.toLowerCase()) { @@ -223,7 +221,11 @@ function validatorReducer(networkId, signedBlocksWindow, validator) { : undefined, uptimePercentage: 1 - - Number(validator.signing_info.missed_blocks_counter) / + Number( + validator.signing_info + ? validator.signing_info.missed_blocks_counter + : 0 + ) / Number(signedBlocksWindow), tokens: atoms(validator.tokens), commissionUpdateTime: validator.commission.update_time, @@ -381,7 +383,7 @@ async function overviewReducer( ) { stakingDenom = denomLookup(stakingDenom) - const totalRewards = _.flatten(rewards) + const totalRewards = flatten(rewards) // this filter is here for multidenom networks. If there is the field denoms inside rewards, we filter // only the staking denom rewards for 'totalRewards' .filter(reward => @@ -445,56 +447,6 @@ async function totalStakeFiatValueReducer( ) } -function getGroupByType(transactionType) { - const transactionGroup = { - [cosmosMessageType.SEND]: 'banking', - [cosmosMessageType.MULTI_SEND]: 'banking', - [cosmosMessageType.CREATE_VALIDATOR]: 'staking', - [cosmosMessageType.EDIT_VALIDATOR]: 'staking', - [cosmosMessageType.DELEGATE]: 'staking', - [cosmosMessageType.UNDELEGATE]: 'staking', - [cosmosMessageType.BEGIN_REDELEGATE]: 'staking', - [cosmosMessageType.UNJAIL]: 'staking', - [cosmosMessageType.SUBMIT_PROPOSAL]: 'governance', - [cosmosMessageType.DEPOSIT]: 'governance', - [cosmosMessageType.VOTE]: 'governance', - [cosmosMessageType.SET_WITHDRAW_ADDRESS]: 'distribution', - [cosmosMessageType.WITHDRAW_DELEGATION_REWARD]: 'distribution', - [cosmosMessageType.WITHDRAW_VALIDATOR_COMMISSION]: 'distribution' - } - - return transactionGroup[transactionType] || 'unknown' -} - -function undelegationEndTimeReducer(transaction) { - if (transaction.tags) { - if (transaction.tags.find(tx => tx.key === `end-time`)) { - return transaction.tags.filter(tx => tx.key === `end-time`)[0].value - } - } else { - return null - } -} - -function formatTransactionsReducer(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 - let filteredMsgs = [] - reversedTxs.forEach(transaction => { - transaction.tx.value.msg.forEach(msg => { - // only push transactions messages supported by Lunie - if (cosmosWhitelistedMessageTypes.has(msg.type.split('/')[1])) { - filteredMsgs.push(msg) - } - }) - transaction.tx.value.msg = filteredMsgs - filteredMsgs = [] - }) - return reversedTxs.map(tx => transactionReducer(tx, reducers)) -} - function extractInvolvedAddresses(transaction) { // If the transaction has failed, it doesn't get tagged if (!Array.isArray(transaction.tags)) return [] @@ -512,316 +464,6 @@ function extractInvolvedAddresses(transaction) { return involvedAddresses } -function transactionReducerV2(transaction, reducers, stakingDenom) { - try { - // 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 { claimMessages, otherMessages } = filteredMessages.reduce( - ({ claimMessages, otherMessages }, message) => { - // we need to aggregate all withdraws as we display them together in one transaction - if (getMessageType(message.type) === lunieMessageTypes.CLAIM_REWARDS) { - claimMessages.push(message) - } else { - otherMessages.push(message) - } - return { claimMessages, otherMessages } - }, - { claimMessages: [], otherMessages: [] } - ) - - // we need to aggregate claim rewards messages in one single one to avoid transaction repetition - const claimMessage = - claimMessages.length > 0 - ? claimRewardsMessagesAggregator(claimMessages) - : undefined - const allMessages = claimMessage - ? otherMessages.concat(claimMessage) // add aggregated claim message - : otherMessages - const returnedMessages = allMessages.map(({ value, type }, index) => ({ - type: getMessageType(type), - hash: transaction.txhash, - key: `${transaction.txhash}_${index}`, - height: transaction.height, - details: transactionDetailsReducer( - getMessageType(type), - value, - reducers, - transaction, - stakingDenom - ), - timestamp: transaction.timestamp, - memo: transaction.tx.value.memo, - fees, - success: - transaction.logs && transaction.logs[index] - ? transaction.logs[index].success || false - : false, - log: - transaction.logs && transaction.logs[index] - ? transaction.logs[index].log - ? transaction.logs[index].log || transaction.logs[0] // failing txs show the first logs - : transaction.logs[0].log || '' - : JSON.parse(transaction.raw_log).message, - involvedAddresses: _.uniq(reducers.extractInvolvedAddresses(transaction)) - })) - return returnedMessages - } catch (error) { - Sentry.withScope(function(scope) { - scope.setExtra('transaction', transaction) - Sentry.captureException(error) - }) - return [] // must return something differ from undefined - } -} - -function transactionsReducerV2(txs, reducers, stakingDenom) { - 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, stakingDenom) - ) - }, []) -} - -// 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) { - const filteredMessages = txMessages.filter( - msg => msg.type.split('/')[1] === `MsgWithdrawDelegationReward` - ) - return filteredMessages.length > 0 ? filteredMessages : null -} - -function transactionReducer(transaction, reducers) { - try { - let fee = coinReducer(false) - if (Array.isArray(transaction.tx.value.fee.amount)) { - fee = coinReducer(transaction.tx.value.fee.amount[0]) - } else { - fee = coinReducer(transaction.tx.value.fee.amount) - } - - const result = { - type: transaction.tx.value.msg[0].type, - group: getGroupByType(transaction.tx.value.msg[0].type), - hash: transaction.txhash, - height: Number(transaction.height), - timestamp: transaction.timestamp, - gasUsed: transaction.gas_used, - gasWanted: transaction.gas_wanted, - success: transaction.logs ? transaction.logs[0].success : false, - log: transaction.logs - ? transaction.logs[0].log - : JSON.parse(transaction.raw_log).message, - memo: transaction.tx.value.memo, - fee, - signature: transaction.tx.value.signatures[0].signature, - value: JSON.stringify(transaction.tx.value.msg[0].value), - raw: transaction, - withdrawValidators: JSON.stringify( - txMultiClaimRewardReducer(transaction.tx.value.msg) - ), - undelegationEndTime: reducers.undelegationEndTimeReducer(transaction) - } - - return result - } catch (err) { - Sentry.withScope(function(scope) { - scope.setExtra('transaction', { - ...transaction, - raw: JSON.stringify(transaction) - }) - Sentry.captureException(err) - }) - return { - raw: transaction - } - } -} - -// 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.CLAIM_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, - transaction, - stakingDenom -) { - 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.CLAIM_REWARDS: - details = claimRewardsDetailsReducer( - message, - reducers, - transaction, - stakingDenom - ) - 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 claimRewardsMessagesAggregator(claimMessages) { - // reduce all withdraw messages to one one collecting the validators from all the messages - const onlyValidatorsAddressesArray = claimMessages.map( - msg => msg.value.validator_address - ) - return { - type: `type/MsgWithdrawDelegationReward`, - value: { - validators: onlyValidatorsAddressesArray - } - } -} - -function sendDetailsReducer(message, reducers) { - return { - from: [message.from_address], - 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, - transaction, - stakingDenom -) { - return { - from: message.validators, - amounts: claimRewardsAmountReducer(transaction, reducers, stakingDenom) - } -} - -function claimRewardsAmountReducer(transaction, reducers, stakingDenom) { - if (!transaction.success) { - return [ - { - amoun: 0, - denom: stakingDenom - } - ] - } - return reducers.rewardCoinReducer( - transaction.events - .find(event => event.type === `transfer`) - .attributes.find(attribute => attribute.key === `amount`).value, - stakingDenom - ) -} - -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, @@ -833,16 +475,11 @@ module.exports = { gasPriceReducer, rewardCoinReducer, balanceReducer, - transactionReducer, undelegationReducer, rewardReducer, overviewReducer, accountInfoReducer, calculateTokens, - undelegationEndTimeReducer, - formatTransactionsReducer, - transactionsReducerV2, - transactionReducerV2, atoms, proposalBeginTime, @@ -851,7 +488,6 @@ module.exports = { getTotalVotePercentage, getValidatorStatus, expectedRewardsPerToken, - getGroupByType, denomLookup, extractInvolvedAddresses } diff --git a/lib/reducers/cosmosV2-reducers.js b/lib/reducers/cosmosV2-reducers.js index 67f5dd6977..9e82a34e96 100644 --- a/lib/reducers/cosmosV2-reducers.js +++ b/lib/reducers/cosmosV2-reducers.js @@ -1,3 +1,6 @@ +const { reverse, sortBy, uniq, uniqWith } = require('lodash') +const Sentry = require('@sentry/node') +const { lunieMessageTypes } = require('../../lib/message-types') const cosmosV0Reducers = require('./cosmosV0-reducers') const { proposalBeginTime, @@ -5,9 +8,184 @@ const { getDeposit, tallyReducer, atoms, - getValidatorStatus + getValidatorStatus, + coinReducer } = cosmosV0Reducers +// 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.CLAIM_REWARDS + case 'MsgSubmitProposal': + return lunieMessageTypes.SUBMIT_PROPOSAL + case 'MsgVote': + return lunieMessageTypes.VOTE + case 'MsgDeposit': + return lunieMessageTypes.DEPOSIT + default: + return lunieMessageTypes.UNKNOWN + } +} + +function sendDetailsReducer(message, reducers) { + return { + from: [message.from_address], + 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, + transaction, + stakingDenom +) { + return { + from: message.validators, + amounts: claimRewardsAmountReducer(transaction, reducers, stakingDenom) + } +} + +function claimRewardsAmountReducer(transaction, reducers, stakingDenom) { + const isTxSucceded = + transaction.success || + transaction.logs.find(({ success }) => success === true) + if (!isTxSucceded) { + return [ + { + amount: 0, + denom: reducers.denomLookup(stakingDenom) + } + ] + } + return reducers.rewardCoinReducer( + transaction.events + .find(event => event.type === `transfer`) + .attributes.find(attribute => attribute.key === `amount`).value, + stakingDenom + ) +} + +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) + } +} + +// function to map cosmos messages to our details format +function transactionDetailsReducer( + type, + message, + reducers, + transaction, + stakingDenom +) { + 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.CLAIM_REWARDS: + details = claimRewardsDetailsReducer( + message, + reducers, + transaction, + stakingDenom + ) + 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 claimRewardsMessagesAggregator(claimMessages) { + // reduce all withdraw messages to one one collecting the validators from all the messages + const onlyValidatorsAddressesArray = claimMessages.map( + msg => msg.value.validator_address + ) + return { + type: `type/MsgWithdrawDelegationReward`, + value: { + validators: onlyValidatorsAddressesArray + } + } +} + function proposalReducer( networkId, proposal, @@ -31,6 +209,89 @@ function proposalReducer( } } +function transactionReducerV2(transaction, reducers, stakingDenom) { + try { + // 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 { claimMessages, otherMessages } = filteredMessages.reduce( + ({ claimMessages, otherMessages }, message) => { + // we need to aggregate all withdraws as we display them together in one transaction + if (getMessageType(message.type) === lunieMessageTypes.CLAIM_REWARDS) { + claimMessages.push(message) + } else { + otherMessages.push(message) + } + return { claimMessages, otherMessages } + }, + { claimMessages: [], otherMessages: [] } + ) + + // we need to aggregate claim rewards messages in one single one to avoid transaction repetition + const claimMessage = + claimMessages.length > 0 + ? claimRewardsMessagesAggregator(claimMessages) + : undefined + const allMessages = claimMessage + ? otherMessages.concat(claimMessage) // add aggregated claim message + : otherMessages + const returnedMessages = allMessages.map(({ value, type }, index) => ({ + type: getMessageType(type), + hash: transaction.txhash, + key: `${transaction.txhash}_${index}`, + height: transaction.height, + details: transactionDetailsReducer( + getMessageType(type), + value, + reducers, + transaction, + stakingDenom + ), + timestamp: transaction.timestamp, + memo: transaction.tx.value.memo, + fees, + success: + transaction.logs && transaction.logs[index] + ? transaction.logs[index].success || false + : false, + log: + transaction.logs && transaction.logs[index] + ? transaction.logs[index].log + ? transaction.logs[index].log || transaction.logs[0] // failing txs show the first logs + : transaction.logs[0].log || '' + : JSON.parse(transaction.raw_log).message, + involvedAddresses: uniq(reducers.extractInvolvedAddresses(transaction)) + })) + return returnedMessages + } catch (error) { + Sentry.withScope(function(scope) { + scope.setExtra('transaction', transaction) + Sentry.captureException(error) + }) + return [] // must return something differ from undefined + } +} + +function transactionsReducerV2(txs, reducers, stakingDenom) { + 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, stakingDenom) + ) + }, []) +} + function delegationReducer(delegation, validator) { return { validatorAddress: delegation.validator_address, @@ -127,7 +388,10 @@ function undelegationEndTimeReducer(transaction) { } module.exports = { + // CosmosV0 Reducers ...cosmosV0Reducers, + transactionsReducerV2, + transactionReducerV2, proposalReducer, delegationReducer, validatorReducer, diff --git a/lib/resolvers.js b/lib/resolvers.js index 37ddb8da12..c01af5a4eb 100644 --- a/lib/resolvers.js +++ b/lib/resolvers.js @@ -9,6 +9,7 @@ const { encodeB32, decodeB32 } = require('./tools') const { UserInputError, withFilter } = require('apollo-server') const { formatBech32Reducer } = require('./reducers/livepeerV0-reducers') const { networkList, networkMap } = require('./networks') +const { getNetworkTransactionGasEstimates } = require('../data/network-fees') const database = require('./database') const config = require('../config.js') const { logOverview } = require('./statistics') @@ -353,13 +354,19 @@ const resolvers = { logOverview(overview, fingerprint) return overview }, - transactions: (_, { networkId, address, pageNumber }, { dataSources }) => - remoteFetch(dataSources, networkId).getTransactions(address, pageNumber), transactionsV2: (_, { networkId, address, pageNumber }, { dataSources }) => remoteFetch(dataSources, networkId).getTransactionsV2( address, pageNumber ), + networkFees: (_, { networkId, transactionType }) => { + return { + gasEstimate: getNetworkTransactionGasEstimates( + networkId, + transactionType + ) + } + }, estimate: () => { try { const gasEstimate = 550000 diff --git a/lib/schema.js b/lib/schema.js index 0fa167f1ef..cab6db7d49 100644 --- a/lib/schema.js +++ b/lib/schema.js @@ -310,6 +310,10 @@ const typeDefs = gql` event(networkId: String!, eventType: String!, ressourceId: String): Event } + type NetworkFees { + gasEstimate: Int! + } + type EstimateResult { gasEstimate: Int error: String @@ -363,16 +367,12 @@ const typeDefs = gql` operatorAddress: String fiatCurrency: String ): [Reward] - transactions( - networkId: String! - address: String! - pageNumber: Int - ): [Transaction] transactionsV2( networkId: String! address: String! pageNumber: Int ): [TransactionV2] + networkFees(networkId: String!, transactionType: String): NetworkFees estimate: EstimateResult! } ` diff --git a/lib/source/akashV0-source.js b/lib/source/akashV0-source.js new file mode 100644 index 0000000000..9b8a771fa0 --- /dev/null +++ b/lib/source/akashV0-source.js @@ -0,0 +1,48 @@ +const TerraV3API = require('./terraV3-source') +const CosmosV0API = require('./cosmosV0-source') + +const gasPrices = [ + { + denom: 'stake', + price: '0.01' + }, + { + denom: 'akash', + price: '0.01' + } +] + +class AkashV0API extends TerraV3API { + setReducers() { + this.reducers = require('../reducers/akashV0-reducers') + this.gasPrices = gasPrices + } + + async getBlockByHeightV2(blockHeight) { + let block, transactions + if (blockHeight) { + const response = await Promise.all([ + this.getRetry(`blocks/${blockHeight}`), + this.getTransactionsV2ByHeight(blockHeight) + ]) + block = response[0] + transactions = response[1] + } else { + block = await this.getRetry(`blocks/latest`) + transactions = await this.getTransactionsV2ByHeight( + block.block.header.height + ) + } + return this.reducers.blockReducer(this.networkId, block, transactions) + } + + async getAllValidators(height) { + return CosmosV0API.prototype.getAllValidators.call(this, height) + } + + async getExpectedReturns(validator) { + return CosmosV0API.prototype.getExpectedReturns.call(this, validator) + } +} + +module.exports = AkashV0API diff --git a/lib/source/cosmosV0-source.js b/lib/source/cosmosV0-source.js index eac4571459..8102aa36d6 100644 --- a/lib/source/cosmosV0-source.js +++ b/lib/source/cosmosV0-source.js @@ -511,23 +511,6 @@ class CosmosV0API extends RESTDataSource { ) } - async loadPaginatedTxs(url, page = 1, totalAmount = 0) { - const pagination = `&limit=1000000000&page=${page}` - let allTxs = [] - - const { txs, total_count } = await this.getRetry(`${url}${pagination}`) - allTxs = allTxs.concat(txs) - - // there is a bug in page_number in gaia-13007 so we can't use is - if (allTxs.length + totalAmount < Number(total_count)) { - return allTxs.concat( - await this.loadPaginatedTxs(url, page + 1, totalAmount + allTxs.length) - ) - } - - return allTxs - } - async getTransactions(address) { this.checkAddress(address) @@ -551,6 +534,23 @@ class CosmosV0API extends RESTDataSource { ]).then(transactionGroups => [].concat(...transactionGroups)) return this.reducers.formatTransactionsReducer(txs, this.reducers) } + + async loadPaginatedTxs(url, page = 1, totalAmount = 0) { + const pagination = `&limit=1000000000&page=${page}` + let allTxs = [] + + const { txs, total_count } = await this.getRetry(`${url}${pagination}`) + allTxs = allTxs.concat(txs) + + // there is a bug in page_number in gaia-13007 so we can't use is + if (allTxs.length + totalAmount < Number(total_count)) { + return allTxs.concat( + await this.loadPaginatedTxs(url, page + 1, totalAmount + allTxs.length) + ) + } + + return allTxs + } } module.exports = CosmosV0API