Skip to content
This repository has been archived by the owner on Jan 15, 2021. It is now read-only.

Deterministic sorting #1513

Merged
merged 13 commits into from
Oct 9, 2020
Merged

Deterministic sorting #1513

merged 13 commits into from
Oct 9, 2020

Conversation

anxolin
Copy link
Contributor

@anxolin anxolin commented Oct 8, 2020

Solves the issue that the sorting is not deterministic.

Changing the implementation on how we get the tokens exposed that our order is not deterministic.
When we changed how we iterate and compose the final list of tokens, it moved our token orders.

  • This PR sorts alphabetically the tokens
  • It also handles a special case. The Native token / and Wrapper comes always first: WETH for mainnet and rinkeby, and wxDAI for xDAI
  • WETH comes second in xDAI network
  • To facilitate the sorting, it was created an artificial derived property (label), with the safeTokenName

image

NOTE:

  • The property label was added, not only for sorting. I think that it's just nice to have already a not nullable displayable name for debugging and for the UI. We use this function over and over in many parts of the app. This PR doesn't do the refactor to take advantage of this new property. There will be a separate issue for that
  • See Make use of the new "label" property in the TokenDetails #1514

@anxolin anxolin mentioned this pull request Oct 8, 2020
29 tasks
@W3stside
Copy link
Contributor

W3stside commented Oct 8, 2020

build is broken

@@ -175,18 +176,56 @@ export function getTokensFactory(factoryParams: {
const tokenDetailsPromises: (Promise<TokenDetails | undefined> | TokenDetails)[] = []
addressToIdMap.forEach((id, tokenAddress) => {
// Resolve the details using the config, otherwise fetch the token
const token: TokenDetails | undefined | Promise<TokenDetails | undefined> = tokensConfigMap.has(tokenAddress)
? tokensConfigMap.get(tokenAddress)
const token: undefined | Promise<TokenDetails | undefined> = tokensConfigMap.has(tokenAddress)
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: can we in the future call unresolved vars promised<varName>? I find it easier to read.

@ghost
Copy link

ghost commented Oct 9, 2020

Travis automatic deployment:

Copy link
Contributor

@Velenir Velenir left a comment

Choose a reason for hiding this comment

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

Consider #1517

Comment on lines +185 to +190
token.then((token) => {
if (token) {
token.label = safeTokenName(token)
}
return token
})
Copy link
Contributor

Choose a reason for hiding this comment

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

As we don't await this specific promise, it could be a race condition
It won't be a race condition in our case because this microtask is scheduled before await Promise.all, but still a bad approach.

Comment on lines +269 to +274
if (a.label < b.label) {
return -1
} else if (a.label > b.label) {
return 1
}
return 0
Copy link
Contributor

Choose a reason for hiding this comment

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

considering what a lable may be (unicode string)and for simpicity, I recommend String.localeCompare (or Intl.collator.compare if you fancy that)

Comment on lines +199 to +209
function _moveTokenToHeadOfArray(tokenAddress: string, tokenList: TokenDetails[]): TokenDetails[] {
const tokenIndex = tokenList.findIndex((t) => t.address === tokenAddress)
if (tokenIndex !== -1) {
const token = tokenList[tokenIndex]
tokenList.splice(tokenIndex, 1)

return [token, ...tokenList]
}

return tokenList
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Please, no 😢
This is like 3 loops more than necessary

Comment on lines +261 to +262
// Sort tokens
const tokenList = _sortTokens(networkId, tokenDetails)
Copy link
Contributor

Choose a reason for hiding this comment

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

This is misleading, Sort is mutative, so we don't get a new tokenList out of that. One might be inclined to treat tokenDetails as unchanged after this line, though we don't do it.

Just writing

_sortTokens(networkId, tokenDetails)

explicitly shows that tokenDetails was mutated

Comment on lines +222 to +223
tokensSorted = _moveTokenToHeadOfArray(WETH_ADDRESS_XDAI, tokensSorted)
return _moveTokenToHeadOfArray(WXDAI_ADDRESS_XDAI, tokensSorted)
Copy link
Contributor

Choose a reason for hiding this comment

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

Please, no no 😭

return tokenList
}

function _sortTokens(networkId: number, tokens: TokenDetails[]): TokenDetails[] {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can do the same in one pass.

@anxolin
Copy link
Contributor Author

anxolin commented Oct 9, 2020

@Velenir we are closing a RC1 with this. I'm ok with the proposal of improvement for the sorting, however the PR #1517 don't have the right order

On monday, when we close 1.5 u can merge this one. I'll use this one for the RC1

@anxolin anxolin merged commit 2a00c36 into release/v1.5 Oct 9, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants