-
Notifications
You must be signed in to change notification settings - Fork 31
Conversation
- remove our HOC helpers which were barely used: withAccount, withContract, withBalance, withConnectDapp - Begin using two Web3 connections - one to the network, and a second to the wallet (which could be a hardware wallet, mobile wallet via WalletConnect, etc.). We will be "connecting the wallet" as a separate step to connecting to Web3 (as Trezor/Ledger don't have a built-in connection to Infura... 😛). The rationale for this is detailed more in #184. - temporarily remove logic for Web3Status - fix Start page to use the react-web3 hook, useWeb3React.
786e8f8
to
46e0568
Compare
Github doesn't support webm/mp4, so here's a brief video on Flowdock of the brutalist functional UI. |
586a1e8
to
9fdf4aa
Compare
53c60f0
to
70148d1
Compare
The LOC on this change scared the bespitters out of me (before I realized there was a huge SVG here, that is). Can we actually split this out to:
? Or would that be too much of a pain? It would be helpful for me to maintain context and keep review turnaround times short, even if each PR is built on the other (as long as the base branch is set to keep the diff to just what that PR is adding). |
@Shadowfiend If that helps us ship faster, then of course. Thanks for explaining why this would help too, that's something I find really useful. |
Feeling kinda documenting, might delete later.
08ea814
to
afaec4e
Compare
Now that I see this updated diff, feels fine as is. Will try and do a full pass today. |
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.
Left some thoughts, questions, and ideas. Feels like we're pretty close, particularly if we punt Trezor to a separate PR.
@@ -22,12 +23,33 @@ const injectedConnector = new InjectedConnector({ | |||
supportedChainIds: SUPPORTED_CHAIN_IDS | |||
}) | |||
|
|||
const ledgerConnector = new LedgerConnector({ | |||
// We use the chainId of mainnet here to workaround an issue with the ledgerjs library. | |||
// It currently throws an error for the default chainId of 1377 used by Geth/Ganache. |
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.
Our chainId is 1101 though, no?
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.
Yah - we may have changed the default for Geth? In either case, they're both >8 bits.
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.
Or geth changed theirs. Can't remember for sure.
// | ||
// At some point, Ledger had to update their firmware, to swap from a uint8 chainId to a uint32 chainId [1]. | ||
// | ||
// They updated their client library with a 'workaround' [2], but it doesn't appear to work. |
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 workaround actually seems to do the opposite, masking any >8-bit chain id to only keep the lowest 8 bits. Guessing it's designed not to screw up when communicating with the ledger, rather than being designed to support larger chain ids?
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.
Guessing it's designed not to screw up when communicating with the ledger, rather than being designed to support larger chain ids?
Yup. Poor wording on my end, deriving from a poor understanding. Basically, Ledger has implemented 32 bit chainID support in their device firmware, but the Ledger Ethereum app still transports the truncated 8 bit ID, I'm guessing. eg. one chain, Piri, has its 32 bit chainID working.
That and my assumptions were wrong - the LedgerSubprovider from 0x uses an older version of @ledgerhq/hw-app-eth, without this workaround. Soooo, going to address that in a bit.
if (wallet == 'Ledger') { | ||
connector = ledgerConnector | ||
} else if (wallet == 'Metamask') { | ||
connector = injectedConnector |
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 may be a good opportunity to use an object to map wallet name -> connector.
src/connectors/ledger.js
Outdated
baseDerivationPath | ||
}) { | ||
super({ | ||
supportedChainIds: [chainId] |
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.
To what extent does the issue with chain ids above break our ability to interact with our internal testnet, out of curiosity?
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 swapping out the current subproviders with ones provided by 0x - they provided more consistent exceptions, that I wasn't hellbent on reimplementing.
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.
They may not support the larger chainID. We'll see what we can do.
src/connectors/ledger.js
Outdated
} | ||
|
||
/** | ||
* @returns {Promise<null>} |
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.
An explanation of what this promise represents would be ideal 😬
Also I tend to use @return
rather than @returns
. @return
is more widely and historically supported both in JS and across languages, so it's just a bit easier of a habit 🤷♂️
The 0x API's are generally of a higher engineering quality. The exceptions encapsulate the error cases better, and they also manage the Ledger Transport lifecycle, which was a flaw of the previous implementation. We use them in keep-core too.
We use @0x/subproviders for the Ledger/Trezor integration. @ledgerhq/hw-app-eth is being upgraded as an older version was installed by accident.
"Stolen" from the Compound dApp. We'll leave these here as a placeholder, until we get the real UX in.
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.
Few more notes; only the one about the annotations is blocking atm I think.
@@ -103,22 +130,52 @@ export const ConnectWalletDialog = ({ shown, onConnected }) => { | |||
} | |||
|
|||
const ConnectToWalletStep = () => { | |||
if(error) { |
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.
Let's at least log this error… We had this issue in the token dApp also where we were displaying a super-generic error and there was no easy way to get to the underlying one.
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, got that covered. The error is set in chooseWallet
, where it is thrown immediately after -
https://github.com/keep-network/tbtc-dapp/blob/master/src/components/lib/ConnectWalletDialog.js#L52
if(chosenWallet == 'Ledger') { | ||
return <> | ||
<header> | ||
<div className="title">Plug In Ledger & Enter Pin</div> |
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 an extra div
here?
return <> | ||
<header> | ||
<div className="title">Connect To A Wallet</div> | ||
<div className="title">Connect to a wallet</div> |
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.
As above re: the div.
const ErrorConnecting = () => { | ||
return <> | ||
<header> | ||
<div className="title">Connect to a wallet</div> |
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.
F' three.
{ error && <p>{error}</p> } | ||
</> | ||
} | ||
|
||
const ConnectedView = () => { | ||
return <div className='connected-view'> | ||
<header> | ||
<div className="title">Connect To A Wallet</div> | ||
<div className="title">Wallet connected</div> |
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.
F' fo'.
@@ -130,6 +187,9 @@ export const ConnectWalletDialog = ({ shown, onConnected }) => { | |||
return <div> | |||
<div className={`modal connect-wallet ${shown ? 'open' : 'closed'}`}> | |||
<div className="modal-body"> | |||
<div className="close"> | |||
<div className="x" onClick={onClose}>╳</div> | |||
</div> |
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 would rather prefer a boutonnière, my dear sir.
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'll chuck that in another PR - we've still got the lingering global styles on <button>
.
* @returns {Promise<Object>} | ||
*/ | ||
async activate(): Promise { | ||
async activate(): Promise<ConnectorUpdate> { |
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.
Uh-oh, looks like some TypeScript annotations sneaked through on this JS file.
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.
Weirdly enough, they didn't break my build? create-react-app / babel must have some support, somewhere in those depths of hell.
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 guarantee it, yes. This is why babel makes me squeamish… I like to know what's actually going on <_<
})) | ||
|
||
engine.start() | ||
let ledgerEthereumClientFactoryAsync = async () => { |
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.
Could be a const
yah?
// Ledger will automatically timeout the U2F "sign" request after `exchangeTimeout` ms. | ||
// This will result in a cryptic error: | ||
// `{name: "TransportError", message: "Failed to sign with Ledger device: U2F DEVICE_INELIGIBLE", ...}` | ||
// Setting the exchange timeout fixes that, although I haven't seen it documented anywhere else in the Ledger docs. |
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.
Fixes it in what sense? The error message is better?
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.
Oops. exchangeTimeout
is set unrealistically low by default (5s or so).
engine.addProvider( | ||
new LedgerSubprovider({ | ||
networkId: this.chainId, | ||
ledgerEthereumClientFactoryAsync, |
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.
What a property name.
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 mean it's no AbstractSingletonProxyFactoryBean... 😄
Work in this branch implements support for Ledger and Trezor for use as Ethereum wallets, and in a future PR that is not far far away, Bitcoin wallets too. It uses web3-react, a well-written library for Ethereum interactions in React, which supports various types of wallets (eg. WalletConnect).
This PR implements "connect a wallet" functionality, with UX inspired from the Uniswap dApp. Some screenshots are attached below to illustrate. Ignore the terrible design until [WIP] is removed.
TransportStatusError: Ledger device: UNKNOWN_ERROR (0x6804)
. Looks like a weird Ledger bug.Depends-On: #195
Epic: #177
Image assets
Logos were taken from: