Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
I
interface
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
LuckySwap
interface
Commits
684258dc
Unverified
Commit
684258dc
authored
Aug 08, 2023
by
Zach Pomerantz
Committed by
GitHub
Aug 08, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: keep a referentially stable connectors list (#7090)
parent
a53e773e
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
87 additions
and
93 deletions
+87
-93
StatusIcon.test.tsx
src/components/Identicon/StatusIcon.test.tsx
+1
-9
StatusIcon.test.tsx.snap
...mponents/Identicon/__snapshots__/StatusIcon.test.tsx.snap
+4
-4
index.tsx
src/components/WalletModal/index.tsx
+1
-3
index.test.tsx
src/components/Web3Provider/index.test.tsx
+26
-29
index.tsx
src/components/Web3Provider/index.tsx
+2
-4
index.test.tsx
src/connection/index.test.tsx
+2
-2
index.ts
src/connection/index.ts
+51
-16
useOrderedConnections.ts
src/hooks/useOrderedConnections.ts
+0
-26
No files found.
src/components/Identicon/StatusIcon.test.tsx
View file @
684258dc
import
{
useWeb3React
}
from
'
@web3-react/core
'
import
{
getConnections
}
from
'
connection
'
import
{
injectedConnection
}
from
'
connection
'
import
{
mocked
}
from
'
test-utils/mocked
'
import
{
render
}
from
'
test-utils/render
'
...
...
@@ -14,15 +14,11 @@ jest.mock('../../hooks/useSocksBalance', () => ({
describe
(
'
StatusIcon
'
,
()
=>
{
describe
(
'
with no account
'
,
()
=>
{
it
(
'
renders children in correct order
'
,
()
=>
{
const
supportedConnections
=
getConnections
()
const
injectedConnection
=
supportedConnections
[
2
]
const
component
=
render
(<
StatusIcon
account=
{
ACCOUNT
}
connection=
{
injectedConnection
}
/>)
expect
(
component
.
getByTestId
(
'
StatusIconRoot
'
)).
toMatchSnapshot
()
})
it
(
'
renders without mini icons
'
,
()
=>
{
const
supportedConnections
=
getConnections
()
const
injectedConnection
=
supportedConnections
[
2
]
const
component
=
render
(<
StatusIcon
account=
{
ACCOUNT
}
connection=
{
injectedConnection
}
showMiniIcons=
{
false
}
/>)
expect
(
component
.
getByTestId
(
'
StatusIconRoot
'
).
children
.
length
).
toEqual
(
0
)
})
...
...
@@ -37,15 +33,11 @@ describe('StatusIcon', () => {
})
it
(
'
renders children in correct order
'
,
()
=>
{
const
supportedConnections
=
getConnections
()
const
injectedConnection
=
supportedConnections
[
2
]
const
component
=
render
(<
StatusIcon
account=
{
ACCOUNT
}
connection=
{
injectedConnection
}
/>)
expect
(
component
.
getByTestId
(
'
StatusIconRoot
'
)).
toMatchSnapshot
()
})
it
(
'
renders without mini icons
'
,
()
=>
{
const
supportedConnections
=
getConnections
()
const
injectedConnection
=
supportedConnections
[
2
]
const
component
=
render
(<
StatusIcon
account=
{
ACCOUNT
}
connection=
{
injectedConnection
}
showMiniIcons=
{
false
}
/>)
expect
(
component
.
getByTestId
(
'
StatusIconRoot
'
).
children
.
length
).
toEqual
(
0
)
})
...
...
src/components/Identicon/__snapshots__/StatusIcon.test.tsx.snap
View file @
684258dc
...
...
@@ -112,9 +112,9 @@ exports[`StatusIcon with account renders children in correct order 1`] = `
class="c1"
>
<img
alt="
WalletConnect
icon"
alt="
Install MetaMask
icon"
class="c2"
src="
walletconnect
-icon.svg"
src="
metamask
-icon.svg"
/>
</div>
<div
...
...
@@ -240,9 +240,9 @@ exports[`StatusIcon with no account renders children in correct order 1`] = `
class="c1"
>
<img
alt="
WalletConnect
icon"
alt="
Install MetaMask
icon"
class="c2"
src="
walletconnect
-icon.svg"
src="
metamask
-icon.svg"
/>
</div>
<div
...
...
src/components/WalletModal/index.tsx
View file @
684258dc
...
...
@@ -2,7 +2,7 @@ import { useWeb3React } from '@web3-react/core'
import
IconButton
from
'
components/AccountDrawer/IconButton
'
import
{
AutoColumn
}
from
'
components/Column
'
import
{
AutoRow
}
from
'
components/Row
'
import
{
getC
onnections
,
networkConnection
}
from
'
connection
'
import
{
c
onnections
,
networkConnection
}
from
'
connection
'
import
{
ActivationStatus
,
useActivationState
}
from
'
connection/activate
'
import
{
isSupportedChain
}
from
'
constants/chains
'
import
{
useEffect
}
from
'
react
'
...
...
@@ -40,8 +40,6 @@ const PrivacyPolicyWrapper = styled.div`
export
default
function
WalletModal
({
openSettings
}:
{
openSettings
:
()
=>
void
})
{
const
{
connector
,
chainId
}
=
useWeb3React
()
const
connections
=
getConnections
()
const
{
activationState
}
=
useActivationState
()
// Keep the network connector in sync with any active user connector to prevent chain-switching on wallet disconnection.
...
...
src/components/Web3Provider/index.test.tsx
View file @
684258dc
import
{
act
,
render
}
from
'
@testing-library/react
'
import
{
InterfaceEventName
,
WalletConnectionResult
}
from
'
@uniswap/analytics-events
'
import
{
initializeConnector
,
MockEIP1193Provider
}
from
'
@web3-react/core
'
import
{
EIP1193
}
from
'
@web3-react/eip1193
'
import
{
MockEIP1193Provider
}
from
'
@web3-react/core
'
import
{
Provider
as
EIP1193Provider
}
from
'
@web3-react/types
'
import
{
sendAnalyticsEvent
,
user
}
from
'
analytics
'
import
{
getConnection
}
from
'
connection
'
import
{
connections
,
getConnection
}
from
'
connection
'
import
{
Connection
,
ConnectionType
}
from
'
connection/types
'
import
useEagerlyConnect
from
'
hooks/useEagerlyConnect
'
import
useOrderedConnections
from
'
hooks/useOrderedConnections
'
import
{
Provider
}
from
'
react-redux
'
import
{
HashRouter
}
from
'
react-router-dom
'
import
store
from
'
state
'
...
...
@@ -20,11 +18,22 @@ jest.mock('analytics', () => ({
user
:
{
set
:
jest
.
fn
(),
postInsert
:
jest
.
fn
()
},
}))
jest
.
mock
(
'
connection
'
,
()
=>
{
const
{
EIP1193
}
=
jest
.
requireActual
(
'
@web3-react/eip1193
'
)
const
{
initializeConnector
,
MockEIP1193Provider
}
=
jest
.
requireActual
(
'
@web3-react/core
'
)
const
{
ConnectionType
}
=
jest
.
requireActual
(
'
connection
'
)
return
{
ConnectionType
,
getConnection
:
jest
.
fn
()
}
const
provider
:
EIP1193Provider
=
new
MockEIP1193Provider
()
const
[
connector
,
hooks
]
=
initializeConnector
((
actions
:
any
)
=>
new
EIP1193
({
actions
,
provider
}))
const
mockConnection
:
Connection
=
{
connector
,
hooks
,
getName
:
()
=>
'
test
'
,
type
:
'
INJECTED
'
as
ConnectionType
,
shouldDisplay
:
()
=>
false
,
}
return
{
ConnectionType
,
getConnection
:
jest
.
fn
(),
connections
:
[
mockConnection
]
}
})
jest
.
mock
(
'
hooks/useEagerlyConnect
'
,
()
=>
jest
.
fn
())
jest
.
mock
(
'
hooks/useOrderedConnections
'
,
()
=>
jest
.
fn
())
jest
.
unmock
(
'
@web3-react/core
'
)
...
...
@@ -45,22 +54,6 @@ const UI = (
)
describe
(
'
Web3Provider
'
,
()
=>
{
let
provider
:
MockEIP1193Provider
&
EIP1193Provider
let
connection
:
Connection
beforeEach
(()
=>
{
provider
=
new
MockEIP1193Provider
()
as
MockEIP1193Provider
&
EIP1193Provider
const
[
connector
,
hooks
]
=
initializeConnector
((
actions
)
=>
new
EIP1193
({
actions
,
provider
}))
connection
=
{
connector
,
hooks
,
getName
:
jest
.
fn
().
mockReturnValue
(
'
test
'
),
type
:
'
INJECTED
'
as
ConnectionType
,
shouldDisplay
:
()
=>
false
,
}
mocked
(
useOrderedConnections
).
mockReturnValue
([
connection
])
})
it
(
'
renders and eagerly connects
'
,
async
()
=>
{
const
result
=
render
(
UI
)
await
act
(
async
()
=>
{
...
...
@@ -71,8 +64,12 @@ describe('Web3Provider', () => {
})
describe
(
'
analytics
'
,
()
=>
{
let
mockProvider
:
MockEIP1193Provider
beforeEach
(()
=>
{
mocked
(
getConnection
).
mockReturnValue
(
connection
)
const
mockConnection
=
connections
[
0
]
mockProvider
=
mockConnection
.
connector
.
provider
as
MockEIP1193Provider
mocked
(
getConnection
).
mockReturnValue
(
mockConnection
)
})
it
(
'
sends event when the active account changes
'
,
async
()
=>
{
...
...
@@ -84,8 +81,8 @@ describe('Web3Provider', () => {
// Act
act
(()
=>
{
p
rovider
.
emitConnect
(
'
0x1
'
)
p
rovider
.
emitAccountsChanged
([
'
0x0000000000000000000000000000000000000000
'
])
mockP
rovider
.
emitConnect
(
'
0x1
'
)
mockP
rovider
.
emitAccountsChanged
([
'
0x0000000000000000000000000000000000000000
'
])
})
// Assert
...
...
@@ -114,14 +111,14 @@ describe('Web3Provider', () => {
// Act
act
(()
=>
{
p
rovider
.
emitConnect
(
'
0x1
'
)
p
rovider
.
emitAccountsChanged
([
'
0x0000000000000000000000000000000000000000
'
])
mockP
rovider
.
emitConnect
(
'
0x1
'
)
mockP
rovider
.
emitAccountsChanged
([
'
0x0000000000000000000000000000000000000000
'
])
})
act
(()
=>
{
p
rovider
.
emitAccountsChanged
([
'
0x0000000000000000000000000000000000000001
'
])
mockP
rovider
.
emitAccountsChanged
([
'
0x0000000000000000000000000000000000000001
'
])
})
act
(()
=>
{
p
rovider
.
emitAccountsChanged
([
'
0x0000000000000000000000000000000000000000
'
])
mockP
rovider
.
emitAccountsChanged
([
'
0x0000000000000000000000000000000000000000
'
])
})
// Assert
...
...
src/components/Web3Provider/index.tsx
View file @
684258dc
...
...
@@ -3,12 +3,11 @@ import { getWalletMeta } from '@uniswap/conedison/provider/meta'
import
{
useWeb3React
,
Web3ReactHooks
,
Web3ReactProvider
}
from
'
@web3-react/core
'
import
{
Connector
}
from
'
@web3-react/types
'
import
{
sendAnalyticsEvent
,
user
}
from
'
analytics
'
import
{
getConnection
}
from
'
connection
'
import
{
connections
,
getConnection
}
from
'
connection
'
import
{
isSupportedChain
}
from
'
constants/chains
'
import
{
RPC_PROVIDERS
}
from
'
constants/providers
'
import
{
TraceJsonRpcVariant
,
useTraceJsonRpcFlag
}
from
'
featureFlags/flags/traceJsonRpc
'
import
useEagerlyConnect
from
'
hooks/useEagerlyConnect
'
import
useOrderedConnections
from
'
hooks/useOrderedConnections
'
import
usePrevious
from
'
hooks/usePrevious
'
import
{
ReactNode
,
useEffect
}
from
'
react
'
import
{
useLocation
}
from
'
react-router-dom
'
...
...
@@ -17,8 +16,7 @@ import { getCurrentPageFromLocation } from 'utils/urlRoutes'
export
default
function
Web3Provider
({
children
}:
{
children
:
ReactNode
})
{
useEagerlyConnect
()
const
connections
=
useOrderedConnections
()
const
connectors
:
[
Connector
,
Web3ReactHooks
][]
=
connections
.
map
(({
hooks
,
connector
})
=>
[
connector
,
hooks
])
const
connectors
=
connections
.
map
<
[
Connector
,
Web3ReactHooks
]
>
(({
hooks
,
connector
})
=>
[
connector
,
hooks
])
return
(
<
Web3ReactProvider
connectors=
{
connectors
}
>
...
...
src/connection/index.test.tsx
View file @
684258dc
import
INJECTED_DARK_ICON
from
'
assets/wallets/browser-wallet-dark.svg
'
import
INJECTED_LIGHT_ICON
from
'
assets/wallets/browser-wallet-light.svg
'
import
{
getConnection
,
getConnections
}
from
'
connection
'
import
{
connections
,
getConnection
}
from
'
connection
'
import
{
ConnectionType
}
from
'
./types
'
...
...
@@ -19,7 +19,7 @@ describe('connection utility/metadata tests', () => {
UserAgentMock
.
isMobile
=
isMobile
global
.
window
.
ethereum
=
ethereum
const
displayed
=
getConnections
()
.
filter
((
c
)
=>
c
.
shouldDisplay
())
const
displayed
=
connections
.
filter
((
c
)
=>
c
.
shouldDisplay
())
const
injected
=
getConnection
(
ConnectionType
.
INJECTED
)
const
coinbase
=
getConnection
(
ConnectionType
.
COINBASE_WALLET
)
const
uniswap
=
getConnection
(
ConnectionType
.
UNISWAP_WALLET_V2
)
...
...
src/connection/index.ts
View file @
684258dc
...
...
@@ -10,6 +10,7 @@ import UNISWAP_LOGO from 'assets/svg/logo.svg'
import
COINBASE_ICON
from
'
assets/wallets/coinbase-icon.svg
'
import
UNIWALLET_ICON
from
'
assets/wallets/uniswap-wallet-icon.png
'
import
WALLET_CONNECT_ICON
from
'
assets/wallets/walletconnect-icon.svg
'
import
{
useSyncExternalStore
}
from
'
react
'
import
{
isMobile
,
isNonIOSPhone
}
from
'
utils/userAgent
'
import
{
RPC_URLS
}
from
'
../constants/networks
'
...
...
@@ -43,7 +44,7 @@ const getIsGenericInjector = () => getIsInjected() && !getIsMetaMaskWallet() &&
const
[
web3Injected
,
web3InjectedHooks
]
=
initializeConnector
<
MetaMask
>
((
actions
)
=>
new
MetaMask
({
actions
,
onError
}))
const
injectedConnection
:
Connection
=
{
export
const
injectedConnection
:
Connection
=
{
getName
:
()
=>
getInjection
().
name
,
connector
:
web3Injected
,
hooks
:
web3InjectedHooks
,
...
...
@@ -78,17 +79,53 @@ export const walletConnectV2Connection: Connection = new (class implements Conne
getIcon
=
()
=>
WALLET_CONNECT_ICON
shouldDisplay
=
()
=>
!
getIsInjectedMobileBrowser
()
private
_connector
=
initializeConnector
<
WalletConnectV2
>
(
this
.
initializer
)
private
activeConnector
=
initializeConnector
<
WalletConnectV2
>
(
this
.
initializer
)
// The web3-react Provider requires referentially stable connectors, so we use proxies to allow lazy connections
// whilst maintaining referential equality.
private
proxyConnector
=
new
Proxy
(
{},
{
get
:
(
target
,
p
,
receiver
)
=>
Reflect
.
get
(
this
.
activeConnector
[
0
],
p
,
receiver
),
getOwnPropertyDescriptor
:
(
target
,
p
)
=>
Reflect
.
getOwnPropertyDescriptor
(
this
.
activeConnector
[
0
],
p
),
getPrototypeOf
:
()
=>
WalletConnectV2
.
prototype
,
set
:
(
target
,
p
,
receiver
)
=>
Reflect
.
set
(
this
.
activeConnector
[
0
],
p
,
receiver
),
}
)
as
(
typeof
this
.
activeConnector
)[
0
]
private
proxyHooks
=
new
Proxy
(
{},
{
get
:
(
target
,
p
,
receiver
)
=>
{
return
()
=>
{
// Because our connectors are referentially stable (through proxying), we need a way to trigger React renders
// from outside of the React lifecycle when our connector is re-initialized. This is done via 'change' events
// with `useSyncExternalStore`:
const
hooks
=
useSyncExternalStore
(
(
onChange
)
=>
{
this
.
onActivate
=
onChange
return
()
=>
(
this
.
onActivate
=
undefined
)
},
()
=>
this
.
activeConnector
[
1
]
)
return
Reflect
.
get
(
hooks
,
p
,
receiver
)()
}
},
}
)
as
(
typeof
this
.
activeConnector
)[
1
]
private
onActivate
?:
()
=>
void
overrideActivate
=
(
chainId
?:
ChainId
)
=>
{
// Always re-create the connector, so that the chainId is updated.
this
.
_connector
=
initializeConnector
((
actions
)
=>
this
.
initializer
(
actions
,
chainId
))
this
.
activeConnector
=
initializeConnector
((
actions
)
=>
this
.
initializer
(
actions
,
chainId
))
this
.
onActivate
?.()
return
false
}
get
connector
()
{
return
this
.
_connector
[
0
]
return
this
.
proxyConnector
}
get
hooks
()
{
return
this
.
_connector
[
1
]
return
this
.
proxyHooks
}
})()
...
...
@@ -135,20 +172,18 @@ const coinbaseWalletConnection: Connection = {
},
}
export
function
getConnections
()
{
return
[
uniwalletWCV2ConnectConnection
,
injectedConnection
,
walletConnectV2Connection
,
coinbaseWalletConnection
,
gnosisSafeConnection
,
networkConnection
,
]
}
export
const
connections
=
[
gnosisSafeConnection
,
uniwalletWCV2ConnectConnection
,
injectedConnection
,
walletConnectV2Connection
,
coinbaseWalletConnection
,
networkConnection
,
]
export
function
getConnection
(
c
:
Connector
|
ConnectionType
)
{
if
(
c
instanceof
Connector
)
{
const
connection
=
getConnections
()
.
find
((
connection
)
=>
connection
.
connector
===
c
)
const
connection
=
connections
.
find
((
connection
)
=>
connection
.
connector
===
c
)
if
(
!
connection
)
{
throw
Error
(
'
unsupported connector
'
)
}
...
...
src/hooks/useOrderedConnections.ts
deleted
100644 → 0
View file @
a53e773e
import
{
getConnection
}
from
'
connection
'
import
{
ConnectionType
}
from
'
connection/types
'
import
{
useMemo
}
from
'
react
'
const
SELECTABLE_WALLETS
=
[
ConnectionType
.
UNISWAP_WALLET_V2
,
ConnectionType
.
INJECTED
,
ConnectionType
.
WALLET_CONNECT_V2
,
ConnectionType
.
COINBASE_WALLET
,
]
export
default
function
useOrderedConnections
()
{
return
useMemo
(()
=>
{
const
orderedConnectionTypes
:
ConnectionType
[]
=
[]
// Always attempt to use to Gnosis Safe first, as we can't know if we're in a SafeContext.
orderedConnectionTypes
.
push
(
ConnectionType
.
GNOSIS_SAFE
)
orderedConnectionTypes
.
push
(...
SELECTABLE_WALLETS
)
// Add network connection last as it should be the fallback.
orderedConnectionTypes
.
push
(
ConnectionType
.
NETWORK
)
return
orderedConnectionTypes
.
map
((
connectionType
)
=>
getConnection
(
connectionType
))
},
[])
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment