Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Wallet] Historical currency conversions in the transaction feed #2446

Merged
merged 34 commits into from
Jan 21, 2020

Conversation

jeanregisser
Copy link
Contributor

@jeanregisser jeanregisser commented Jan 15, 2020

Description

This PR enables historical currency conversions in the transaction feed.

Main highlights:

  • Implemented the updated schema in blockchain-api which allows querying transactions only for a specific token (cUSD on the home screen, cGLD on the exchange screen), retrieving
    amounts in local currency, and later on will make it easy to paginate the data as proposed in https://docs.google.com/document/d/1ryfz7Gd0bk9QQHDBCWyaBy2AeOui63hgp-HdFtyBTyc/edit
  • Fixed the broken gql-gen tool and made GraphQL related code type safe again by using graphql-codegen for the client. (we should use it for blockchain-api too)
  • Started moving displayed money amounts into the CurrencyDisplay component. This component takes care of doing the actual currency conversions when needed. It will evolve as we move more of the existing code to it. It already simplified the feed items components.
  • Refactored code to use the same TransactionsList component for both the home and exchange screens and added tests for it.

We should probably run graphql-codegen as part of our React Native dev startup script to spot any type issues with the blockchain-api we're connecting to. I'll address that in a separate PR.

In the ExchangeFeedItem fragment, the amount field might feel redundant as it's either the makerAmount or the takerAmount with the addition of the sign (+/-), which we could derive client side. My main goal was to make the interface right first and optimize later when needed.

The TransactionsList.text.tsx test outputs console logs about invalid/missing fragments, this is caused by the Apollo MockProvider context missing details about the interface type we're using. I tried to pass the right fragmentMatcher like we do in the normal client (see https://www.apollographql.com/docs/react/data/fragments/#fragments-on-unions-and-interfaces)
but it then failed to return any data to the querying component.
In short, the test works as expected but outputs a lot of misleading noise.

Finally, this PR looks a bit big, but there are a lot of simple renames and snapshots changes, so hopefully shouldn't be too hard to review 🙏

Tested

  • Confirmed that converted local amounts in the transaction feed now use historical rates.
  • Added new tests.

Other changes

  • Currency conversion API now outputs a string instead of a number to prevent rounding issues.
  • The amounts in the transactions API are now string as well for the same reason stated above.
  • Memoized gold exchange rates queries (per requests).
  • Fixed a redux state update that was done in a non immutable way.
  • I had a problem with the test suite when running with --runInBand like in the CI and it was caused by the apollo query component not being unmounted after the test.
    I upgraded react-native-testing-library to be able to cleanup mounted components after testing. See https://github.com/callstack/react-native-testing-library/blob/master/docs/API.md#cleanup
    I decided to make that behavior global for all tests as I feel it's the right thing to do for us.
    See b99484a
    I just had to change one test which relied on a component being mounted between test.
    See 6a90310
    Let me know if you have any concern with this.

Related issues

Backwards compatibility

Yes.

// Find the event related to the queried token
const tokenEvent = [inEvent, outEvent].find((event) => event.tokenSymbol === args.token)
if (tokenEvent) {
const timestamp = new BigNumber(inEvent.timeStamp).toNumber()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would parseInt do the job here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We generally opt for BigNum over parseInt

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did not know that. Is the reason because BigNumber is more universal and can handle different input formats compare to parseInt?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exactly

@i1skn
Copy link
Contributor

i1skn commented Jan 15, 2020

Great work!!! See a couple of non-blocker comments I've left :)

@codecov
Copy link

codecov bot commented Jan 16, 2020

Codecov Report

Merging #2446 into master will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@           Coverage Diff            @@
##           master    #2446    +/-   ##
========================================
  Coverage   74.79%   74.79%            
========================================
  Files         281      281            
  Lines        7922     7922            
  Branches      724     1013   +289     
========================================
  Hits         5925     5925            
  Misses       1894     1894            
  Partials      103      103
Flag Coverage Δ
#mobile 74.79% <ø> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 7e0ec79...5b12586. Read the comment docs.

Copy link
Contributor

@i1skn i1skn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the tremendous improvement 🚢 !

Copy link
Contributor

@jmrossy jmrossy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall really nice work! Some comments below but nothing major

@@ -214,6 +218,107 @@ export class BlockscoutAPI extends RESTDataSource {
)
return rewards.sort((a, b) => b.timestamp - a.timestamp)
}

async getTransactions(args: TransactionArgs) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you leave a comment or rename this to clarify how it differs from the existing getTokenTransactions and getFeedEvents methods?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! getFeedEvents was kept for backward compatibility, it is intended to be removed at some point.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Up to you then if you want to remove it now or later. Please leave TODOs explaining this

txHashToEventTransactions.set(tx.hash, currentTX)
}

await this.ensureTokenAddresses()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a new change in this PR but we should consider reworking this bit or at least leave a comment. This design of forcing users of token addresses to first call this method to ensure they're set is problematic. Easy to mess up. Would be better if the token addresses had getters that fetched them when null. cc @annakaz

Copy link
Contributor Author

@jeanregisser jeanregisser Jan 17, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also I suspect this call is slowing down queries given a new data source is instantiated for each request.


await this.ensureTokenAddresses()
// Generate final events
txHashToEventTransactions.forEach((transactions: BlockscoutTransaction[], txhash: string) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we DRY this up with the getFeedEvents method above? Or is one being deprecated?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes getFeedEvents is being deprecated.

return dataSources.blockscoutAPI.getFeedEvents(args)
},
rewards: async (_source: any, args: EventArgs, { dataSources }: Context) => {
return dataSources.blockscoutAPI.getFeedRewards(args)
},
transactions: async (_source: any, args: TransactionArgs, context: Context) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My problem with transaction is that it's too vague. It could be anything from an ERC20 token transfer to a verification request to a smart contract deployment. Is there a more descriptive name we could use?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, tokenTransactions feels like the right name then, what do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done 👍

comment: string
status?: TransactionStatus
// TODO: fee needs to be added here
export type Event = Exchange | Transfer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you kept the old Event interface for backwards compatibility with older app versions? But the next time we ship the app, we'll be resetting the network too and forcing users to update. We could actually remove all that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed! Let's remove it then.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll remove the deprecated code after this PR is merged to prevent breaking things unnecessarily given blockchain-api has to be redeployed.

value: divideByWei(transferNotification.value),
currency: resolveCurrency(transferNotification.currency),
amount: {
amount: divideByWei(transferNotification.value).toString(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another common source of confusion is whether or not a value is in wei or not. You don't need to fix in this PR but would be cool if we had a wei to type that and avoid potential mistakes.

Copy link
Contributor Author

@jeanregisser jeanregisser Jan 17, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I will definitely continue thinking about this as we improve currencies handling.

@jeanregisser jeanregisser added the automerge Have PR merge automatically when checks pass label Jan 20, 2020
@celo-ci-bot-user celo-ci-bot-user merged commit d558461 into master Jan 21, 2020
@celo-ci-bot-user celo-ci-bot-user deleted the jeanregisser/transaction-feed-refactor branch January 21, 2020 14:29
aaronmgdr added a commit that referenced this pull request Jan 21, 2020
* master:
  [Wallet] Historical currency conversions in the transaction feed (#2446)
  CLI relock fix (#2464)
  Update copyright year + inline button  (#2468)

# Conflicts:
#	yarn.lock
aaronmgdr added a commit that referenced this pull request Jan 21, 2020
* master: (25 commits)
  Add react-testing-utils + Fix Analytics (#2437)
  collect coverage on web (#2415)
  Add callouts to serve text messages in regions (#2458)
  [Wallet] Historical currency conversions in the transaction feed (#2446)
  CLI relock fix (#2464)
  Update copyright year + inline button  (#2468)
  Voting bot for stake off (#2327)
  Change order of profile info (#2454)
  [Wallet] Fix type check regression for components wrapped by our custom `withTranslation` (#2457)
  Unfreeze rewards by default (#2452)
  Baklava and baklavastaging deploys (#2421)
  Fix coin colors  (#2441)
  Make governance CLI more usable (#2428)
  Slashing params for stake off phase 2 (#2418)
  [Wallet] Rollback zeroSync toggle in case it was not successful (#2434)
  [Wallet] Cleanup unused StateProps references (#2439)
  Add unit tests and cli checks for validator hotfix interaction (#2340)
  Add proper Spanish translations (#2427)
  Catch exceptions during polling (#2432)
  Add unfreeze-contracts command to celotool (#2433)
  ...

# Conflicts:
#	packages/web/src/brandkit/common/MobileMenu.test.tsx
#	yarn.lock
aaronmgdr added a commit that referenced this pull request Jan 21, 2020
* master:
  Add react-testing-utils + Fix Analytics (#2437)
  collect coverage on web (#2415)
  Add callouts to serve text messages in regions (#2458)
  [Wallet] Historical currency conversions in the transaction feed (#2446)
  CLI relock fix (#2464)
  Update copyright year + inline button  (#2468)
  Voting bot for stake off (#2327)
  Change order of profile info (#2454)
  [Wallet] Fix type check regression for components wrapped by our custom `withTranslation` (#2457)
  Unfreeze rewards by default (#2452)

# Conflicts:
#	packages/web/src/analytics/analytics.test.ts
#	packages/web/src/brandkit/common/MobileMenu.test.tsx
#	yarn.lock
aaronmgdr added a commit that referenced this pull request Jan 22, 2020
* master:
  add celo.org/about#contributors id (#2488)
  [Wallet] Fix integration build firebase db url on Android (#2495)
  Fixes governance CLI bugs encountered while running election contract upgrade (#2482)
  Add validator:signed-blocks command and fix validator:status bug (#2456)
  Bump @celo/celocli version to 0.0.34 (#2420)
  Fix Logo + backers number change (#2453)
  Improve election efficiency by short circuiting (#2475)
  Page for Experience / BrandKit / Composition (#2462)
  Configure the time to wait for text messages (#2450)
  Add react-testing-utils + Fix Analytics (#2437)
  collect coverage on web (#2415)
  Add callouts to serve text messages in regions (#2458)
  [Wallet] Historical currency conversions in the transaction feed (#2446)
  CLI relock fix (#2464)
  Update copyright year + inline button  (#2468)
  Voting bot for stake off (#2327)
aaronmgdr added a commit that referenced this pull request Jan 23, 2020
* master: (72 commits)
  [Wallet] Fix incorrect empty state on the gold tab (#2510)
  Added ingress resource for celostats DNS (#2480)
  Fix celotool testnet deploy (#2501)
  [Wallet] Navigate to wallet home after payment request (#2500)
  Require Consent for tracking globally (#2489)
  new academic papers + minor fix to web events (#2502)
  [Wallet] Fetch tobin tax for exchanges (#1492)
  add celo.org/about#contributors id (#2488)
  [Wallet] Fix integration build firebase db url on Android (#2495)
  Fixes governance CLI bugs encountered while running election contract upgrade (#2482)
  Add validator:signed-blocks command and fix validator:status bug (#2456)
  Bump @celo/celocli version to 0.0.34 (#2420)
  Fix Logo + backers number change (#2453)
  Improve election efficiency by short circuiting (#2475)
  Page for Experience / BrandKit / Composition (#2462)
  Configure the time to wait for text messages (#2450)
  Add react-testing-utils + Fix Analytics (#2437)
  collect coverage on web (#2415)
  Add callouts to serve text messages in regions (#2458)
  [Wallet] Historical currency conversions in the transaction feed (#2446)
  ...

# Conflicts:
#	.circleci/config.yml
#	packages/web/src/brandkit/common/Page.tsx
#	packages/web/src/logos/LogoLightBg.tsx
#	packages/web/static/locales/en/brand.json
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
automerge Have PR merge automatically when checks pass
Projects
None yet
4 participants