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

Initial E2E Working Setup #1

Closed
wants to merge 28 commits into from
Closed

Initial E2E Working Setup #1

wants to merge 28 commits into from

Conversation

W3stside
Copy link
Contributor

@W3stside W3stside commented Aug 16, 2019

This PR is large. But can be visualised and broken down into parts:

This provides an E2E testable app. Lots of the commits are just setup related. The main files are explained below. All following PRs will be focused.

Please follow the README to test - but should run simply via npm i && npm run start:example-ts

  1. src/api/web3.ts sets up Web3Api singleton able to be passed around
    a. Tested inside ./tests/api/index.test.ts
  2. src/components/Web3ConnectButton.tsx pulls web3connect button and uses the initialised Web3Api
  3. src/components/DisplayWeb3.tsx takes the instantiated Web3Api and displays:
    a. Account
    b. ETH Balance
    c. Network Name
    d. Client (Provider) Version
  4. ./examples/ts-frontend is used to test the components/setup fns in points 1-3

@W3stside W3stside added the WIP label Aug 16, 2019
@W3stside W3stside self-assigned this Aug 16, 2019

Open app in `localhost:1234`

For wallet connect, please use `test.walletconnect.org`
Copy link

Choose a reason for hiding this comment

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

I tried to connect with the Gnosis Safe, it worked the connection. It didn't work the disconnection.

Also, after refreshing, if I try to connect again with wallet connect, it's not showing the QR, and instead I see:
image

Copy link

Choose a reason for hiding this comment

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

Not sure if it's related, but the previous wallet in the local storage, but I cannot change it:

image

Copy link

Choose a reason for hiding this comment

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

For trust wallet, is not detecting the address and network info either:

image

Copy link

Choose a reason for hiding this comment

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

With test.walletconnect.org it worked the connection.

image

But it didn't work the disconnection.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah I was also having Safe issue, think the bridge URI was down when testing. Walletconnect integration is buggy at best. Not sure how to proceed on that front but will test more

Copy link

Choose a reason for hiding this comment

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

I think we should extract the wallet connect part from this PR.
We can create one PR that just adds Wallet Connect integration, then merge it when it's fully working?

If we have some specific case it's not working, like the ones I shared, we can make it easily reproducible and share with Wallet Connect team.

"react-dom": "^16.8.6",
"react-hot-loader": "^4.12.10",
"styled-components": "^4.3.2",
"web3": "^2.0.0-alpha.1",
Copy link

Choose a reason for hiding this comment

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

In the doc of web3, they recommend not using 2.0 for production.

https://web3js.readthedocs.io/en/v2.0.0-alpha.1/getting-started.html

image

Should we use 1.0 instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@Velenir thoughts here?

Copy link
Contributor

Choose a reason for hiding this comment

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

In my experience 2.0.0 is more stable than 1.0. Certainly has more fixes included. Remember they were both renamed from beta only a month ago. 1.0 is more stable in the sense that truffle and co. are using it, that's all

On a semi-related note, I think we may be better off not dealing with web3 at all, only provider. Leave web3 (or etherjs or whatever) instantiation to anyone using the library. Everything from accountsChange to WC session management can be done with provider only

Copy link

Choose a reason for hiding this comment

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

Yes, right now is a copy of 1.0 but if they write that is not mainnet ready it's because they expect breaking changes.

I think the app we have to do is super basic, it should be ok to work with "not the last version". If there's a big reason to jump for the unstable, we could review it, otherwise I think is not worth it at this point. We can revisit this in a few months.

package.json Outdated Show resolved Hide resolved
src/api/utils.ts Outdated Show resolved Hide resolved
src/api/utils.ts Outdated
@@ -0,0 +1,20 @@
export const windowLoaded = new Promise((accept, reject) => {
if (typeof window === 'undefined') {
return accept()
Copy link

Choose a reason for hiding this comment

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

Why is the promise resolved if there's no window object?
Shouldn't be this handled as an exception?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

better as to not block the rest of the logic that isn't entirely window dependent - though tbh I haven't tested this logic with a non window exposing device

Copy link
Contributor

Choose a reason for hiding this comment

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

Me thinks, leave waiting on window to the library users. If they need it, like ens only ever set up react on window.onload

Copy link

@anxolin anxolin Aug 27, 2019

Choose a reason for hiding this comment

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

But if the method is "windowLoaded" and there's no window, it seems or to return a failed promise.

Also, note that you already fail if it doesn't allow you to subscribe the listener:
image

You don't block the user. The one using the library decides how to handle the exception. You shouldn't decide for the user of the util function what to do if there's something wrong, like "no window"

} catch (error) {
if (error.readyState === 4 && (error.status === 400 || error.status === 200)) {
// the endpoint is active
console.debug('API/WEB3.ts catch block => Success')
Copy link

Choose a reason for hiding this comment

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

What does this mean?
Will be provider = new Web3(url) always initialized in this case?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

for readOnly mode, yes

Copy link

@anxolin anxolin Aug 27, 2019

Choose a reason for hiding this comment

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

I don't get:
1. What is a null provider provider = new Web3(null) (it's asked already in other comment)

  1. The logic: if the fetch fails, what is this branch doing. It seems complicated:
    image

  2. This logic. Are we always using metamask if it's installed or do we allow the user to choose. For example, if we want to use wallet connect, it will prompt in the metamask extension.
    Also, do we really need to hardcode the development ganache as a fallback?

image

} else {
console.debug('API/WEB3.ts => No web3 instance injected. Falling back to null provider.')
readOnly = true
provider = new Web3(null)
Copy link

Choose a reason for hiding this comment

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

What is a null provider?
Also, what is "readOnly"? If there's no connection with the node you can't read, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

App loads, no blocking, no thrown error, user can see the app, better UX

Copy link

Choose a reason for hiding this comment

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

Mmm, I'm not sure about this. This getProvider returns a promise: Promise<Web3>

This means, that if something is wrong, we can handle the case.

One solution is to do something like:
resolve(null) signaling, there's no Web3 object cause we didn't connect the wallet yet. The app can react and handle that case. So you can still have a good UX

src/api/web3.ts Outdated Show resolved Hide resolved
src/api/web3.ts Outdated Show resolved Hide resolved
src/api/web3.ts Outdated Show resolved Hide resolved
Copy link

@anxolin anxolin left a comment

Choose a reason for hiding this comment

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

I tried to do a full review before my trip, but I didn't manage. Anyways, I think it's enough review, we can review first the open conversations, since there are many already :D

It think it's a super good start. I understand that this PR got big and next iterations should be smaller in changes and scope, I think it's ok this one time exception, but it made the review much more complicated and I think for both sides, since we'll have a lot of things to discuss here.

Many of the discussions opened aim to open discussions about project structure, code style and so on, because I think it's good to do this exercise now so we are all in sync

src/api/web3.ts Outdated Show resolved Hide resolved
src/api/web3.ts Outdated Show resolved Hide resolved
src/api/web3.ts Outdated Show resolved Hide resolved
src/api/web3.ts Outdated Show resolved Hide resolved
src/api/web3.ts Outdated Show resolved Hide resolved
src/api/web3.ts Outdated Show resolved Hide resolved
src/api/web3.ts Outdated Show resolved Hide resolved

/* Provider Specific */
const setProvider = web3.setProvider.bind(web3)
const resetProvider = (): void => setProvider(web3.currentProvider)
Copy link

Choose a reason for hiding this comment

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

Why do we need resetProvider?

Copy link

Choose a reason for hiding this comment

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

I think if we don't use it, we should remove.
If it's a bug of a provider, we can review that specific case

src/components/App.tsx Outdated Show resolved Hide resolved
src/components/DisplayWeb3.tsx Show resolved Hide resolved
1. ethereum utils imported from Web3
2. misc utils
3. exported from index
1. global file with constants
2. types file (global)
3. removed typings.d.ts + old utils file
1. allow synthetic imports into examples ts
2. removed unused lines
1. moved types into global
2. clarified names of fns
3. removed async catching
4. fixed tests to naming changes
Copy link

@anxolin anxolin left a comment

Choose a reason for hiding this comment

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

All positive changes since last review!

I added several replies and comments.
One of the most important things to get this merged, is to separate wallet connect from this PR until it's stable.

const setter = async (): Promise<void> => {
const accountsProm = web3Api.getAccounts()
const networkNameProm = web3Api.getNetworkName()
const clientVersionProm = web3Api.web3.currentProvider.send('web3_clientVersion', [])
Copy link

Choose a reason for hiding this comment

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

I think there was already a web3 method for this.

Anyways. How do you handle the null provider thing we are discussing in the other thread.
As I wrote in the other thead. If the wallet is not connected. I think it's better to have a null web3Api and handle that case.

If the wallet re-connects, this component function will be called again with a non-null value

Copy link
Contributor

Choose a reason for hiding this comment

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

No universal method for that. Won't work with some wallets, and this method will

Copy link

Choose a reason for hiding this comment

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

But one of my comments is, I saw in other parts of the PR that web3Api.web3.currentProvider can be null in some cases.

This will crash if it's the case, right?

Anyways, I also think is nor right to do the new Web3(null), we should handle the case differently too (there's other conversation for this topic)

Also, I would argue that the web3Api.web3.currentProvider.send(...) is a bit coupled, and since you already have an interface for interacting web3Api it would be simpler and more readable to do sth like web3Api.sendRpc(...)


export const DisplayWeb3: React.FC<DisplayWeb3Props> = ({ web3Api }) => {
const [account, setAccount] = useState<string>()

Copy link

Choose a reason for hiding this comment

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

supernit: I would get rid of this line breaks


useEffect(() => {
const setter = async (): Promise<void> => {
const accountsProm = web3Api.getAccounts()
Copy link

Choose a reason for hiding this comment

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

I think it's better not to shorten the word promise :)

image

clientVersionProm,
])

ReactDOM.unstable_batchedUpdates(() => {
Copy link

Choose a reason for hiding this comment

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

what is unstable_batchedUpdates?
I'm not super familiar, made me curious the word "unstable"

Copy link
Contributor

Choose a reason for hiding this comment

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

It's what they use internally in event handlers to avoid multiple rerenders.
React-redux also uses it, so even if it's called unstable everyone does it

const [web3Api, setWeb3FrontendAPI] = useState<Web3Api>()

return (
<>
Copy link

Choose a reason for hiding this comment

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

I think this is not needed

<Web3Connect.Button
providerOptions={{
walletconnect: {
bridge: 'https://safe-walletconnect.dev.gnosisdev.com/',
Copy link

Choose a reason for hiding this comment

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

Is this hardcoded?

What is this bridge?

GOERLI: 'GOERLI',
}

export const NETWORK_ID_TO_NAME = {
Copy link

Choose a reason for hiding this comment

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

Why is not enough a single object for the networks?

return getWeb3Api(options)
} catch (error) {
console.error('launchDappUI Error!', error)
throw new Error(error)
Copy link

Choose a reason for hiding this comment

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

Why do we rethrow. Shouldn't we handle this error?

getTransaction: (txHash: string) => Promise<Transaction>
getTransactionReceipt: (txHash: string) => Promise<TransactionReceipt>
// Utils
isReadOnly: () => boolean
Copy link

Choose a reason for hiding this comment

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

I don't think we need this. I would think this only make sense if we allow users to "sign in" by entering an address, so we show a read only version.

I think what you were using this for is to display a limited UI when there's an error connecting the wallet. But I think we can take other approaches (there's other open discussions about it, so no need to add it here too )

@@ -0,0 +1,3 @@
import { isAddress, toBN, isBN, isBigNumber, fromAscii, toHex, toWei, fromWei } from 'web3-utils'

export { isAddress, toBN, isBN, isBigNumber, fromAscii, toHex, toWei, fromWei }
Copy link

Choose a reason for hiding this comment

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

Good one! I think it was the right move to move these utils from the API to here.

@anxolin
Copy link

anxolin commented Aug 27, 2019

@W3stside I see it has the WIP tag. Is there anything else you want to include in this PR?

Copy link

@anxolin anxolin left a comment

Choose a reason for hiding this comment

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

Lest resolve the open conversations before this gets merged.

@Velenir
Copy link
Contributor

Velenir commented Nov 11, 2019

superseded but the waterfall 💧

@Velenir Velenir closed this Nov 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants