-
Notifications
You must be signed in to change notification settings - Fork 465
[instant][types][order-utils][asset-buyer] Move over and clean up features from zrx-buyer #1131
[instant][types][order-utils][asset-buyer] Move over and clean up features from zrx-buyer #1131
Conversation
@@ -26,18 +57,18 @@ export const InstantHeading: React.StatelessComponent<InstantHeadingProps> = pro | |||
<SelectedAssetAmountInput fontSize="45px" /> | |||
<Container display="inline-block" marginLeft="10px"> | |||
<Text fontSize="45px" fontColor={ColorOption.white} textTransform="uppercase"> | |||
rep | |||
zrx |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove hardcoded zrx values
@@ -0,0 +1,4 @@ | |||
export const sraApiUrl = 'https://api.radarrelay.com/0x/v2/'; | |||
export const zrxContractAddress = '0xe41d2489571d322189246dafa5ebde1f4699f498'; | |||
export const zrxDecimals = 18; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove hard-coded zrx values
// invalidate the last buy quote. | ||
dispatch({ type: ActionTypes.UPDATE_LATEST_BUY_QUOTE, data: undefined }); | ||
// reset our buy state | ||
dispatch({ type: ActionTypes.UPDATE_SELECTED_ASSET_BUY_STATE, data: AsyncProcessState.NONE }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
create action creators? would allow us to have typed actions...
fetchAndDispatchToStore: async () => { | ||
let ethUsdPriceStr = '0'; | ||
try { | ||
ethUsdPriceStr = await coinbaseApi.getEthUsdPrice(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
coinbase API call should return BigNumber
import { BigNumber } from '@0xproject/utils'; | ||
import * as _ from 'lodash'; | ||
|
||
import { Action, ActionTypes } from '../types'; | ||
import { Action, ActionTypes, AsyncProcessState } from '../types'; | ||
|
||
export interface State { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add state for Provider
, and other things required to remove hard-coded values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not going to do this for now. Should be done when we implement different wallets.
…into feature/instant/move-features-over-from-zrx-buyer
@@ -10,10 +10,13 @@ export interface AmountInputProps { | |||
fontColor?: ColorOption; | |||
fontSize?: string; | |||
value?: BigNumber; | |||
onChange?: (value?: BigNumber) => void; | |||
onChange: (value?: BigNumber) => void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is value undefined if the input is empty?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep! This is what made most sense to me.
|
||
export interface AssetAmountInputProps extends AmountInputProps { | ||
assetData?: string; | ||
onChange: (value?: BigNumber, assetData?: string) => void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are we ever going to have a case where we have a value but not an assetData?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In practice no, but those two things can be undefined
independently and that case needs to be handled somewhere. The other option is to not render something, but in the event that we are rendering, we need to handle it here.
</Container> | ||
); | ||
} | ||
private readonly _getLabel = (): string => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe this can have a clearer name like _getAssetSymbolLabel
const { assetData, onChange, ...rest } = this.props; | ||
return ( | ||
<Container> | ||
<AmountInput {...rest} onChange={this._handleChange} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a design / polish nit, I think we want the text in this input to be right justified so that if you have typed just '5' then the character '5' is close to the symbol label
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do in a future PR (added to my list)
</Button> | ||
</Container> | ||
); | ||
const boundNoop = _.noop.bind(_); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we extract this out into a util or something since we are using it in multiple components? Also do we necessarily need to bind here? I suppose the linter may complain?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The linter complains yes.
}) => { | ||
const fontWeight = shouldEmphasize ? 700 : 400; | ||
const usdFormatter = shouldConvertEthToUnitAmount ? format.ethBaseAmountInUsd : format.ethUnitAmountInUsd; | ||
const ethFormatter = shouldConvertEthToUnitAmount ? format.ethBaseAmount : format.ethUnitAmount; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need to bind format here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't use this
in format, and even if we did we would be fine because we are using arrow functions. In general I think it's a bit awkward to use the function
keyword in es6 since we have classes and arrow functions. In es5, all we had was function
and that was for both classes and functions.
try { | ||
const txnHash = await assetBuyer.executeBuyQuoteAsync(this.props.buyQuote, { | ||
// HACK: There is a calculation issue in asset-buyer. ETH is refunded anyway so just over-estimate. | ||
ethAmount: this.props.buyQuote.worstCaseQuoteInfo.totalEthAmount.mul(2), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think this ethAmount should come from the buyQuoteInfo stored in redux so there is less chance we end up executing a buy thats different from what we are presenting in the order details
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not technically possible in this implementation, but yes the API allows that... I feel like that's ok?
const provider = getProvider(); | ||
|
||
export const assetBuyer = AssetBuyer.getAssetBuyerForStandardRelayerAPIUrl(provider, sraApiUrl, { | ||
expiryBufferSeconds: 300, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should already be the default
import { BigNumber } from '@0xproject/utils'; | ||
|
||
const baseEndpoint = 'https://api.coinbase.com/v2'; | ||
export const coinbaseApi = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is coinbase the best choice for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure, jw what thought process you had when choosing the coinbase API to supply the price. Some things to consider, support for other currencies for localization, rate limiting, downtime, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I looked into a few options but did not do a crazy thorough comparison. Coinbase has 3 req / sec, 10k req / hour per IP, which seems reasonable. They also support other (fiat) currencies. Not much info available on downtime. Do you know of other APIs?
@@ -10,10 +10,13 @@ export interface AmountInputProps { | |||
fontColor?: ColorOption; | |||
fontSize?: string; | |||
value?: BigNumber; | |||
onChange?: (value?: BigNumber) => void; | |||
onChange: (value?: BigNumber) => void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just curious -- why move this from being optional to being required but having a default no-op? is this a pattern we want to follow for callbacks?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So yea this is a bit confusing. @types/react and ts > 3.0.0 added understanding of defaultProps
. So the way you think about the Props
interface is that it's the internal interface (in this case, callback is not optional). However, if you have a default value the compiler knows that you actually don't have to pass the prop in (ie. the external interface is a function of internal interface + defaultProps).
So in practice it's not required, has default no-ops, so internally you can assume it's not undefined.
And yea I like this pattern :P
UPDATE_LATEST_BUY_QUOTE = 'UPDATE_LATEST_BUY_QUOTE', | ||
} | ||
|
||
export const actions = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typed actions! 🎉 🙌 💯
|
||
const mapStateToProps = (state: State, _ownProps: LatestBuyQuoteOrderDetailsProps): ConnectedState => ({ | ||
// use the worst case quote info | ||
buyQuoteInfo: _.get(state, 'latestBuyQuote.worstCaseQuoteInfo'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor: I would prefer to grab the worstCaseInfo without using _.get
to keep the typesafety (i.e. ensuring worstCaseQuoteInfo
is actually a property of latestBuyQuote
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a package https://github.com/rimeto/ts-optchain. The API is a bit ugly but it gives us the best of both worlds. Open to discussing, but didn't take long to include.
@@ -0,0 +1,6 @@ | |||
import { BigNumber } from '@0xproject/utils'; | |||
export const BIG_NUMBER_ZERO = new BigNumber(0); | |||
export const sraApiUrl = 'https://api.radarrelay.com/0x/v2/'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will we make this more configurable in a separate PR?
…into feature/instant/move-features-over-from-zrx-buyer
import { ethDecimals } from '../constants'; | ||
|
||
export const format = { | ||
ethBaseAmount: (ethBaseAmount?: BigNumber, decimalPlaces: number = 4, defaultText: string = '0 ETH'): string => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might be good to add unit tests here
packages/instant/src/util/format.ts
Outdated
if (_.isUndefined(ethUnitAmount) || _.isUndefined(ethUsdPrice)) { | ||
return defaultText; | ||
} | ||
return `$${ethUnitAmount.mul(ethUsdPrice).round(decimalPlaces)}`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sometimes this results in strings with 1 decimal place like: "$3.7"
…into feature/instant/move-features-over-from-zrx-buyer
a377e21
to
dbf5be6
Compare
Description
Straight port of features:
assetData
andassetMetaData
.I also changed some types but then ended up not needing the change... but still seems like a good change? Basically we should control all unions of different asset data types, such that the build fails if we add a type to that union, assuming we are using a switch statement in the implementation of the function that is meant to handle all asset data types.
Testing instructions
Types of changes
Checklist:
[WIP]
if necessary.[sol-cov] Fixed bug
.