chore: moving conedison/provider to interface (#7119)
* chore: moving provider from coned to interface * moving signing over to interface * updating lockfile * dedup * use d3-array build for jest * downgrading jest/types * Revert "downgrading jest/types" This reverts commit 88d3746c00dcd98275be18a4b8af0314ae4329ad.
This commit is contained in:
parent
31d0c3c9b3
commit
6ec9bb7362
@ -56,10 +56,10 @@ module.exports = {
|
||||
'\\.css\\.ts$': '@vanilla-extract/jest-transform',
|
||||
'\\.(t|j)sx?$': '@swc/jest',
|
||||
},
|
||||
// Use @uniswap/conedison's build directly, as jest does not support its exports.
|
||||
transformIgnorePatterns: ['@uniswap/conedison/provider'],
|
||||
// Use d3-arrays's build directly, as jest does not support its exports.
|
||||
transformIgnorePatterns: ['d3-array'],
|
||||
moduleNameMapper: {
|
||||
'@uniswap/conedison/provider': '@uniswap/conedison/dist/provider',
|
||||
'd3-array': 'd3-array/dist/d3-array.min.js',
|
||||
},
|
||||
})
|
||||
},
|
||||
|
@ -94,7 +94,7 @@
|
||||
"@types/array.prototype.flat": "^1.2.1",
|
||||
"@types/array.prototype.flatmap": "^1.2.2",
|
||||
"@types/d3": "^6.7.1",
|
||||
"@types/jest": "^25.2.1",
|
||||
"@types/jest": "^27.0.1",
|
||||
"@types/lingui__core": "^2.7.1",
|
||||
"@types/lingui__macro": "^2.7.4",
|
||||
"@types/lingui__react": "^2.8.3",
|
||||
@ -192,7 +192,6 @@
|
||||
"@types/react-window-infinite-loader": "^1.0.6",
|
||||
"@uniswap/analytics": "^1.4.0",
|
||||
"@uniswap/analytics-events": "^2.17.0",
|
||||
"@uniswap/conedison": "^1.8.0",
|
||||
"@uniswap/governance": "^1.0.2",
|
||||
"@uniswap/liquidity-staker": "^1.0.2",
|
||||
"@uniswap/merkle-distributor": "^1.0.1",
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { CustomUserProperties, InterfaceEventName, WalletConnectionResult } from '@uniswap/analytics-events'
|
||||
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'
|
||||
@ -13,6 +12,7 @@ import { ReactNode, useEffect } from 'react'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
import { useConnectedWallets } from 'state/wallets/hooks'
|
||||
import { getCurrentPageFromLocation } from 'utils/urlRoutes'
|
||||
import { getWalletMeta } from 'utils/walletMeta'
|
||||
|
||||
export default function Web3Provider({ children }: { children: ReactNode }) {
|
||||
useEagerlyConnect()
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { signTypedData } from '@uniswap/conedison/provider/signing'
|
||||
import { AllowanceTransfer, MaxAllowanceTransferAmount, PERMIT2_ADDRESS, PermitSingle } from '@uniswap/permit2-sdk'
|
||||
import { CurrencyAmount, Token } from '@uniswap/sdk-core'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
@ -9,6 +8,7 @@ import { useSingleCallResult } from 'lib/hooks/multicall'
|
||||
import ms from 'ms'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { toReadableError, UserRejectedRequestError } from 'utils/errors'
|
||||
import { signTypedData } from 'utils/signing'
|
||||
import { didUserReject } from 'utils/swapErrorToUserReadableMessage'
|
||||
|
||||
const PERMIT_EXPIRATION = ms(`30d`)
|
||||
@ -77,7 +77,6 @@ export function useUpdatePermitAllowance(
|
||||
}
|
||||
|
||||
const { domain, types, values } = AllowanceTransfer.getPermitData(permit, PERMIT2_ADDRESS, chainId)
|
||||
// Use conedison's signTypedData for better x-wallet compatibility.
|
||||
const signature = await signTypedData(provider.getSigner(account), domain, types, values)
|
||||
onPermitSignature?.({ ...permit, signature })
|
||||
return
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { BigNumber } from '@ethersproject/bignumber'
|
||||
import * as Sentry from '@sentry/react'
|
||||
import { SwapEventName } from '@uniswap/analytics-events'
|
||||
import { signTypedData } from '@uniswap/conedison/provider/signing'
|
||||
import { Percent } from '@uniswap/sdk-core'
|
||||
import { DutchOrder, DutchOrderBuilder } from '@uniswap/uniswapx-sdk'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
@ -11,6 +10,7 @@ import { useCallback } from 'react'
|
||||
import { DutchOrderTrade, TradeFillType } from 'state/routing/types'
|
||||
import { trace } from 'tracing/trace'
|
||||
import { UserRejectedRequestError } from 'utils/errors'
|
||||
import { signTypedData } from 'utils/signing'
|
||||
import { didUserReject, swapErrorToUserReadableMessage } from 'utils/swapErrorToUserReadableMessage'
|
||||
|
||||
const DEFAULT_START_TIME_PADDING_SECONDS = 30
|
||||
|
154
src/utils/signing.test.ts
Normal file
154
src/utils/signing.test.ts
Normal file
@ -0,0 +1,154 @@
|
||||
import { ExternalProvider, JsonRpcProvider, JsonRpcSigner, Web3Provider } from '@ethersproject/providers'
|
||||
import { signTypedData } from 'utils/signing'
|
||||
|
||||
type Mutable<T> = { -readonly [P in keyof T]: T[P] }
|
||||
|
||||
describe('signing', () => {
|
||||
describe('signTypedData', () => {
|
||||
const wallet = '0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826'
|
||||
const domain = {
|
||||
name: 'Ether Mail',
|
||||
version: '1',
|
||||
chainId: '1',
|
||||
verifyingContract: '0xcccccccccccccccccccccccccccccccccccccccc',
|
||||
}
|
||||
|
||||
const types = {
|
||||
Person: [
|
||||
{ name: 'name', type: 'string' },
|
||||
{ name: 'wallet', type: 'address' },
|
||||
],
|
||||
Mail: [
|
||||
{ name: 'from', type: 'Person' },
|
||||
{ name: 'to', type: 'Person' },
|
||||
{ name: 'contents', type: 'string' },
|
||||
],
|
||||
}
|
||||
|
||||
const value = {
|
||||
from: {
|
||||
name: 'Cow',
|
||||
wallet,
|
||||
},
|
||||
to: {
|
||||
name: 'Bob',
|
||||
wallet: '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
|
||||
},
|
||||
contents: 'Hello, Bob!',
|
||||
}
|
||||
|
||||
let signer: JsonRpcSigner
|
||||
beforeEach(() => {
|
||||
signer = new JsonRpcProvider().getSigner()
|
||||
jest.spyOn(signer, 'getAddress').mockResolvedValue(wallet)
|
||||
})
|
||||
|
||||
function itFallsBackToEthSignIfUnimplemented(signingMethod: string) {
|
||||
it.each(['not found', 'not implemented'])(`falls back to eth_sign if ${signingMethod} is %s`, async (message) => {
|
||||
const send = jest
|
||||
.spyOn(signer.provider, 'send')
|
||||
.mockImplementationOnce((method) => {
|
||||
if (method === signingMethod) return Promise.reject({ message: `method ${message}` })
|
||||
throw new Error('Unimplemented')
|
||||
})
|
||||
.mockImplementationOnce((method) => {
|
||||
if (method === 'eth_sign') return Promise.resolve()
|
||||
throw new Error('Unimplemented')
|
||||
})
|
||||
jest.spyOn(console, 'warn').mockImplementation(() => undefined)
|
||||
|
||||
await signTypedData(signer, domain, types, value)
|
||||
expect(console.warn).toHaveBeenCalledWith(
|
||||
expect.stringContaining('signTypedData: wallet does not implement EIP-712, falling back to eth_sign'),
|
||||
expect.anything()
|
||||
)
|
||||
expect(send).toHaveBeenCalledTimes(2)
|
||||
expect(send).toHaveBeenCalledWith(signingMethod, [wallet, expect.anything()])
|
||||
expect(send).toHaveBeenCalledWith('eth_sign', [wallet, expect.anything()])
|
||||
const hash = send.mock.lastCall[1]?.[1]
|
||||
expect(hash).toBe('0xbe609aee343fb3c4b28e1df9e632fca64fcfaede20f02e86244efddf30957bd2')
|
||||
})
|
||||
}
|
||||
|
||||
function itFailsIfRejected(signingMethod: string) {
|
||||
it('fails if rejected', async () => {
|
||||
const send = jest.spyOn(signer.provider, 'send').mockImplementationOnce((method) => {
|
||||
if (method === signingMethod) return Promise.reject(new Error('User rejected'))
|
||||
throw new Error('Unimplemented')
|
||||
})
|
||||
|
||||
await expect(async () => await signTypedData(signer, domain, types, value)).rejects.toThrow('User rejected')
|
||||
expect(send).toHaveBeenCalledTimes(1)
|
||||
expect(send).toHaveBeenCalledWith(signingMethod, [wallet, expect.anything()])
|
||||
const data = send.mock.lastCall[1]?.[1]
|
||||
expect(JSON.parse(data)).toEqual(expect.objectContaining({ domain, message: value }))
|
||||
})
|
||||
}
|
||||
|
||||
it('signs using eth_signTypedData_v4', async () => {
|
||||
const send = jest.spyOn(signer.provider, 'send').mockImplementationOnce((method) => {
|
||||
if (method === 'eth_signTypedData_v4') return Promise.resolve()
|
||||
throw new Error('Unimplemented')
|
||||
})
|
||||
|
||||
await signTypedData(signer, domain, types, value)
|
||||
expect(send).toHaveBeenCalledTimes(1)
|
||||
expect(send).toHaveBeenCalledWith('eth_signTypedData_v4', [wallet, expect.anything()])
|
||||
const data = send.mock.lastCall[1]?.[1]
|
||||
expect(JSON.parse(data)).toEqual(expect.objectContaining({ domain, message: value }))
|
||||
})
|
||||
|
||||
itFallsBackToEthSignIfUnimplemented('eth_signTypedData_v4')
|
||||
itFailsIfRejected('eth_signTypedData_v4')
|
||||
|
||||
describe('wallets which do not support eth_signTypedData_v4', () => {
|
||||
describe.each(['SafePal Wallet', 'Ledger Wallet Connect'])('%s', (name) => {
|
||||
beforeEach(() => {
|
||||
const web3Provider = signer.provider as Mutable<Web3Provider>
|
||||
web3Provider.provider = {
|
||||
isWalletConnect: true,
|
||||
session: { peer: { metadata: { name } } },
|
||||
} as ExternalProvider
|
||||
})
|
||||
|
||||
it('signs using eth_signTypedData', async () => {
|
||||
const send = jest.spyOn(signer.provider, 'send').mockImplementationOnce((method) => {
|
||||
if (method === 'eth_signTypedData') return Promise.resolve()
|
||||
throw new Error('Unimplemented')
|
||||
})
|
||||
|
||||
await signTypedData(signer, domain, types, value)
|
||||
expect(send).toHaveBeenCalledTimes(1)
|
||||
expect(send).toHaveBeenCalledWith('eth_signTypedData', [wallet, expect.anything()])
|
||||
const data = send.mock.lastCall[1]?.[1]
|
||||
expect(JSON.parse(data)).toEqual(expect.objectContaining({ domain, message: value }))
|
||||
})
|
||||
|
||||
itFallsBackToEthSignIfUnimplemented('eth_signTypedData')
|
||||
itFailsIfRejected('eth_signTypedData')
|
||||
})
|
||||
})
|
||||
|
||||
describe('TrustWallet fallback for eth_signTypedData_v4', () => {
|
||||
beforeEach(() => {
|
||||
const web3Provider = signer.provider as Mutable<Web3Provider>
|
||||
web3Provider.provider = {
|
||||
isWalletConnect: true,
|
||||
session: { peer: { metadata: { name: 'Trust Wallet' } } },
|
||||
} as ExternalProvider
|
||||
})
|
||||
|
||||
it('signs using eth_sign', async () => {
|
||||
jest.spyOn(console, 'warn').mockReturnValue()
|
||||
const send = jest.spyOn(signer.provider, 'send').mockImplementation((method) => {
|
||||
if (method === 'eth_sign') return Promise.resolve()
|
||||
throw new Error('TrustWalletConnect.WCError error 1')
|
||||
})
|
||||
|
||||
await signTypedData(signer, domain, types, value)
|
||||
expect(send).toHaveBeenCalledTimes(2)
|
||||
expect(send).toHaveBeenCalledWith('eth_sign', [wallet, expect.anything()])
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
64
src/utils/signing.ts
Normal file
64
src/utils/signing.ts
Normal file
@ -0,0 +1,64 @@
|
||||
import type { TypedDataDomain, TypedDataField } from '@ethersproject/abstract-signer'
|
||||
import { _TypedDataEncoder } from '@ethersproject/hash'
|
||||
import type { JsonRpcProvider, JsonRpcSigner } from '@ethersproject/providers'
|
||||
import { getWalletMeta, WalletType } from 'utils/walletMeta'
|
||||
|
||||
// These are WalletConnect peers which do not implement eth_signTypedData_v4, but *do* implement eth_signTypedData.
|
||||
// They are special-cased so that signing will still use EIP-712 (which is safer for the user).
|
||||
const WC_PEERS_LACKING_V4_SUPPORT = ['SafePal Wallet', 'Ledger Wallet Connect']
|
||||
|
||||
// Assumes v4 support by default, except for known wallets.
|
||||
function supportsV4(provider: JsonRpcProvider): boolean {
|
||||
const meta = getWalletMeta(provider)
|
||||
if (meta) {
|
||||
const { type, name } = meta
|
||||
if (name) {
|
||||
if (type === WalletType.WALLET_CONNECT && name && WC_PEERS_LACKING_V4_SUPPORT.includes(name)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Signs TypedData with EIP-712, if available, or else by falling back to eth_sign.
|
||||
* Calls eth_signTypedData_v4, or eth_signTypedData for wallets with incomplete EIP-712 support.
|
||||
*
|
||||
* @see https://github.com/ethers-io/ethers.js/blob/c80fcddf50a9023486e9f9acb1848aba4c19f7b6/packages/providers/src.ts/json-rpc-provider.ts#L334
|
||||
*/
|
||||
export async function signTypedData(
|
||||
signer: JsonRpcSigner,
|
||||
domain: TypedDataDomain,
|
||||
types: Record<string, TypedDataField[]>,
|
||||
// Use Record<string, any> for the value to match the JsonRpcSigner._signTypedData signature.
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
value: Record<string, any>
|
||||
) {
|
||||
// Populate any ENS names (in-place)
|
||||
const populated = await _TypedDataEncoder.resolveNames(domain, types, value, (name: string) => {
|
||||
return signer.provider.resolveName(name) as Promise<string>
|
||||
})
|
||||
|
||||
const method = supportsV4(signer.provider) ? 'eth_signTypedData_v4' : 'eth_signTypedData'
|
||||
const address = (await signer.getAddress()).toLowerCase()
|
||||
const message = JSON.stringify(_TypedDataEncoder.getPayload(populated.domain, types, populated.value))
|
||||
|
||||
try {
|
||||
return await signer.provider.send(method, [address, message])
|
||||
} catch (error) {
|
||||
// If eth_signTypedData is unimplemented, fall back to eth_sign.
|
||||
if (
|
||||
typeof error.message === 'string' &&
|
||||
(error.message.match(/not (found|implemented)/i) ||
|
||||
error.message.match(/TrustWalletConnect.WCError error 1/) ||
|
||||
error.message.match(/Missing or invalid/))
|
||||
) {
|
||||
console.warn('signTypedData: wallet does not implement EIP-712, falling back to eth_sign', error.message)
|
||||
const hash = _TypedDataEncoder.hash(populated.domain, types, populated.value)
|
||||
return await signer.provider.send('eth_sign', [address, hash])
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
87
src/utils/walletMeta.test.ts
Normal file
87
src/utils/walletMeta.test.ts
Normal file
@ -0,0 +1,87 @@
|
||||
import type { ExternalProvider } from '@ethersproject/providers'
|
||||
import { JsonRpcProvider } from '@ethersproject/providers'
|
||||
import type WalletConnectProvider from '@walletconnect/ethereum-provider'
|
||||
import { getWalletMeta, WalletMeta, WalletType } from 'utils/walletMeta'
|
||||
|
||||
class MockJsonRpcProvider extends JsonRpcProvider {
|
||||
name = 'JsonRpcProvider'
|
||||
arg: string
|
||||
|
||||
constructor(arg?: unknown) {
|
||||
super()
|
||||
this.arg = JSON.stringify(arg)
|
||||
}
|
||||
}
|
||||
|
||||
const WC_META = { name: 'name', description: 'description', url: 'url', icons: [] }
|
||||
|
||||
class MockWalletConnectProviderV2 extends MockJsonRpcProvider {
|
||||
name = WalletType.WALLET_CONNECT
|
||||
provider: WalletConnectProvider
|
||||
|
||||
constructor(metadata: typeof WC_META | null) {
|
||||
super(metadata)
|
||||
this.provider = { isWalletConnect: true, session: { peer: { metadata } } } as unknown as WalletConnectProvider
|
||||
}
|
||||
}
|
||||
|
||||
class MockInjectedProvider extends MockJsonRpcProvider {
|
||||
name = WalletType.INJECTED
|
||||
provider: ExternalProvider
|
||||
|
||||
constructor(provider: Record<string, boolean | undefined>) {
|
||||
super(provider)
|
||||
this.provider = {
|
||||
isConnected() {
|
||||
return true
|
||||
},
|
||||
...provider,
|
||||
} as ExternalProvider
|
||||
}
|
||||
}
|
||||
|
||||
const testCases: [MockJsonRpcProvider, WalletMeta | undefined][] = [
|
||||
[new MockJsonRpcProvider(), undefined],
|
||||
[new MockWalletConnectProviderV2(null), { type: WalletType.WALLET_CONNECT, agent: '(WalletConnect)' }],
|
||||
[
|
||||
new MockWalletConnectProviderV2(WC_META),
|
||||
{ type: WalletType.WALLET_CONNECT, agent: 'name (WalletConnect)', ...WC_META },
|
||||
],
|
||||
[new MockInjectedProvider({}), { type: WalletType.INJECTED, agent: '(Injected)', name: undefined }],
|
||||
[
|
||||
new MockInjectedProvider({ isMetaMask: false }),
|
||||
{ type: WalletType.INJECTED, agent: '(Injected)', name: undefined },
|
||||
],
|
||||
[
|
||||
new MockInjectedProvider({ isMetaMask: true }),
|
||||
{ type: WalletType.INJECTED, agent: 'MetaMask (Injected)', name: 'MetaMask' },
|
||||
],
|
||||
[
|
||||
new MockInjectedProvider({ isTest: true, isMetaMask: true }),
|
||||
{ type: WalletType.INJECTED, agent: 'Test MetaMask (Injected)', name: 'Test' },
|
||||
],
|
||||
[
|
||||
new MockInjectedProvider({ isCoinbaseWallet: true, qrUrl: undefined }),
|
||||
{ type: WalletType.INJECTED, agent: 'CoinbaseWallet (Injected)', name: 'CoinbaseWallet' },
|
||||
],
|
||||
[
|
||||
new MockInjectedProvider({ isCoinbaseWallet: true, qrUrl: true }),
|
||||
{ type: WalletType.INJECTED, agent: 'CoinbaseWallet qrUrl (Injected)', name: 'CoinbaseWallet' },
|
||||
],
|
||||
[
|
||||
new MockInjectedProvider({ isA: true, isB: false }),
|
||||
{ type: WalletType.INJECTED, agent: 'A (Injected)', name: 'A' },
|
||||
],
|
||||
[
|
||||
new MockInjectedProvider({ isA: true, isB: true }),
|
||||
{ type: WalletType.INJECTED, agent: 'A B (Injected)', name: 'A' },
|
||||
],
|
||||
]
|
||||
|
||||
describe('meta', () => {
|
||||
describe.each(testCases)('getWalletMeta/getWalletName returns the project meta/name', (provider, meta) => {
|
||||
it(`${provider?.name} ${provider.arg}`, () => {
|
||||
expect(getWalletMeta(provider)).toEqual(meta)
|
||||
})
|
||||
})
|
||||
})
|
91
src/utils/walletMeta.ts
Normal file
91
src/utils/walletMeta.ts
Normal file
@ -0,0 +1,91 @@
|
||||
import type { ExternalProvider, JsonRpcProvider, Web3Provider } from '@ethersproject/providers'
|
||||
import type WalletConnectProvider from '@walletconnect/ethereum-provider'
|
||||
|
||||
function isWeb3Provider(provider: JsonRpcProvider): provider is Web3Provider {
|
||||
return 'provider' in provider
|
||||
}
|
||||
|
||||
function isWalletConnectProvider(provider: ExternalProvider): provider is WalletConnectProvider {
|
||||
return (provider as WalletConnectProvider).isWalletConnect
|
||||
}
|
||||
|
||||
export enum WalletType {
|
||||
WALLET_CONNECT = 'WalletConnect',
|
||||
INJECTED = 'Injected',
|
||||
}
|
||||
|
||||
/**
|
||||
* WalletMeta for WalletConnect or Injected wallets.
|
||||
*
|
||||
* For WalletConnect wallets, name, description, url, and icons are taken from WalletConnect's peerMeta
|
||||
* v1: @see https://docs.walletconnect.com/1.0/specs#session-request
|
||||
* v2: @see https://docs.walletconnect.com/2.0/specs/clients/core/pairing/data-structures#metadata
|
||||
*
|
||||
* For Injected wallets, the name is derived from the `is*` properties on the provider (eg `isCoinbaseWallet`).
|
||||
*/
|
||||
export interface WalletMeta {
|
||||
type: WalletType
|
||||
/**
|
||||
* The agent string of the wallet, for use with analytics/debugging.
|
||||
* Denotes the wallet's provenance - analagous to a User String - including all `is*` properties and the type.
|
||||
*
|
||||
* Some injected wallets are used different ways (eg with/without spoofing MetaMask).
|
||||
* The agent will capture these differences, while the name will not.
|
||||
*
|
||||
* @example 'CoinbaseWallet qUrl (Injected)'
|
||||
*/
|
||||
agent: string
|
||||
/**
|
||||
* The name of the wallet, for use with UI.
|
||||
*
|
||||
* @example 'CoinbaseWallet'
|
||||
*/
|
||||
name?: string
|
||||
description?: string
|
||||
url?: string
|
||||
icons?: string[]
|
||||
}
|
||||
|
||||
function getWalletConnectMeta(provider: WalletConnectProvider): WalletMeta {
|
||||
const metadata = provider.session?.peer.metadata
|
||||
return {
|
||||
type: WalletType.WALLET_CONNECT,
|
||||
agent: metadata ? `${metadata.name} (WalletConnect)` : '(WalletConnect)',
|
||||
...metadata,
|
||||
}
|
||||
}
|
||||
|
||||
function getInjectedMeta(provider: ExternalProvider & Record<string, unknown>): WalletMeta {
|
||||
const properties = Object.getOwnPropertyNames(provider)
|
||||
const names =
|
||||
properties
|
||||
.filter((name) => name.match(/^is.*$/) && (provider as Record<string, unknown>)[name] === true)
|
||||
.map((name) => name.slice(2)) ?? []
|
||||
|
||||
// Many wallets spoof MetaMask by setting `isMetaMask` along with their own identifier,
|
||||
// so we sort MetaMask last so that these wallets' names come first.
|
||||
names.sort((a, b) => (a === 'MetaMask' ? 1 : b === 'MetaMask' ? -1 : 0))
|
||||
|
||||
// Coinbase Wallet can be connected through an extension or a QR code, with `qrUrl` as the only differentiator,
|
||||
// so we capture `qrUrl` in the agent string.
|
||||
if (properties.includes('qrUrl') && provider['qrUrl']) {
|
||||
names.push('qrUrl')
|
||||
}
|
||||
|
||||
return {
|
||||
type: WalletType.INJECTED,
|
||||
agent: [...names, '(Injected)'].join(' '),
|
||||
name: names[0],
|
||||
// TODO(WEB-2914): Populate description, url, and icons for known wallets.
|
||||
}
|
||||
}
|
||||
|
||||
export function getWalletMeta(provider: JsonRpcProvider): WalletMeta | undefined {
|
||||
if (!isWeb3Provider(provider)) return undefined
|
||||
|
||||
if (isWalletConnectProvider(provider.provider)) {
|
||||
return getWalletConnectMeta(provider.provider)
|
||||
} else {
|
||||
return getInjectedMeta(provider.provider)
|
||||
}
|
||||
}
|
69
yarn.lock
69
yarn.lock
@ -3408,16 +3408,6 @@
|
||||
slash "^3.0.0"
|
||||
write-file-atomic "^4.0.2"
|
||||
|
||||
"@jest/types@^25.5.0":
|
||||
version "25.5.0"
|
||||
resolved "https://registry.npmjs.org/@jest/types/-/types-25.5.0.tgz"
|
||||
integrity sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw==
|
||||
dependencies:
|
||||
"@types/istanbul-lib-coverage" "^2.0.0"
|
||||
"@types/istanbul-reports" "^1.1.1"
|
||||
"@types/yargs" "^15.0.0"
|
||||
chalk "^3.0.0"
|
||||
|
||||
"@jest/types@^26.6.2":
|
||||
version "26.6.2"
|
||||
resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e"
|
||||
@ -5672,14 +5662,6 @@
|
||||
dependencies:
|
||||
"@types/istanbul-lib-coverage" "*"
|
||||
|
||||
"@types/istanbul-reports@^1.1.1":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz"
|
||||
integrity sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==
|
||||
dependencies:
|
||||
"@types/istanbul-lib-coverage" "*"
|
||||
"@types/istanbul-lib-report" "*"
|
||||
|
||||
"@types/istanbul-reports@^3.0.0":
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff"
|
||||
@ -5687,13 +5669,13 @@
|
||||
dependencies:
|
||||
"@types/istanbul-lib-report" "*"
|
||||
|
||||
"@types/jest@*", "@types/jest@^25.2.1":
|
||||
version "25.2.3"
|
||||
resolved "https://registry.npmjs.org/@types/jest/-/jest-25.2.3.tgz"
|
||||
integrity sha512-JXc1nK/tXHiDhV55dvfzqtmP4S3sy3T3ouV2tkViZgxY/zeUkcpQcQPGRlgF4KmWzWW5oiWYSZwtCB+2RsE4Fw==
|
||||
"@types/jest@*", "@types/jest@^27.0.1":
|
||||
version "27.5.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.5.2.tgz#ec49d29d926500ffb9fd22b84262e862049c026c"
|
||||
integrity sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA==
|
||||
dependencies:
|
||||
jest-diff "^25.2.1"
|
||||
pretty-format "^25.2.1"
|
||||
jest-matcher-utils "^27.0.0"
|
||||
pretty-format "^27.0.0"
|
||||
|
||||
"@types/js-yaml@^4.0.0":
|
||||
version "4.0.5"
|
||||
@ -6209,11 +6191,6 @@
|
||||
react "^18.2.0"
|
||||
react-dom "^18.2.0"
|
||||
|
||||
"@uniswap/conedison@^1.8.0":
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@uniswap/conedison/-/conedison-1.8.0.tgz#60fcfa1475780350a719510ccee1f6a49f8c5cf8"
|
||||
integrity sha512-EeC37bbrd4sJnqW3TxNhExdWUBvzyJDhbTXcbDzFdBh/bg5sOCu1NbYJEnrjwBHEfewc9nF2OjEzejJFyJUx9A==
|
||||
|
||||
"@uniswap/default-token-list@^11.2.0":
|
||||
version "11.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@uniswap/default-token-list/-/default-token-list-11.2.0.tgz#f7babd37b8f2f1d5c724bd4689be93c4aedd9205"
|
||||
@ -10391,11 +10368,6 @@ didyoumean@^1.2.2:
|
||||
resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037"
|
||||
integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==
|
||||
|
||||
diff-sequences@^25.2.6:
|
||||
version "25.2.6"
|
||||
resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.2.6.tgz"
|
||||
integrity sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg==
|
||||
|
||||
diff-sequences@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327"
|
||||
@ -13905,16 +13877,6 @@ jest-dev-server@^9.0.0:
|
||||
tree-kill "^1.2.2"
|
||||
wait-on "^7.0.1"
|
||||
|
||||
jest-diff@^25.2.1:
|
||||
version "25.5.0"
|
||||
resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-25.5.0.tgz"
|
||||
integrity sha512-z1kygetuPiREYdNIumRpAHY6RXiGmp70YHptjdaxTWGmA085W3iCnXNx0DhflK3vwrKmrRWyY1wUpkPMVxMK7A==
|
||||
dependencies:
|
||||
chalk "^3.0.0"
|
||||
diff-sequences "^25.2.6"
|
||||
jest-get-type "^25.2.6"
|
||||
pretty-format "^25.5.0"
|
||||
|
||||
jest-diff@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.5.1.tgz#a07f5011ac9e6643cf8a95a462b7b1ecf6680def"
|
||||
@ -14031,11 +13993,6 @@ jest-fetch-mock@^3.0.3:
|
||||
cross-fetch "^3.0.4"
|
||||
promise-polyfill "^8.1.3"
|
||||
|
||||
jest-get-type@^25.2.6:
|
||||
version "25.2.6"
|
||||
resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.6.tgz"
|
||||
integrity sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig==
|
||||
|
||||
jest-get-type@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1"
|
||||
@ -14124,7 +14081,7 @@ jest-leak-detector@^29.6.1:
|
||||
jest-get-type "^29.4.3"
|
||||
pretty-format "^29.6.1"
|
||||
|
||||
jest-matcher-utils@^27.5.1:
|
||||
jest-matcher-utils@^27.0.0, jest-matcher-utils@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab"
|
||||
integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==
|
||||
@ -17333,16 +17290,6 @@ pretty-error@^4.0.0:
|
||||
lodash "^4.17.20"
|
||||
renderkid "^3.0.0"
|
||||
|
||||
pretty-format@^25.2.1, pretty-format@^25.5.0:
|
||||
version "25.5.0"
|
||||
resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-25.5.0.tgz"
|
||||
integrity sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ==
|
||||
dependencies:
|
||||
"@jest/types" "^25.5.0"
|
||||
ansi-regex "^5.0.0"
|
||||
ansi-styles "^4.0.0"
|
||||
react-is "^16.12.0"
|
||||
|
||||
pretty-format@^26.6.2:
|
||||
version "26.6.2"
|
||||
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93"
|
||||
@ -17353,7 +17300,7 @@ pretty-format@^26.6.2:
|
||||
ansi-styles "^4.0.0"
|
||||
react-is "^17.0.1"
|
||||
|
||||
pretty-format@^27.0.2, pretty-format@^27.5.1:
|
||||
pretty-format@^27.0.0, pretty-format@^27.0.2, pretty-format@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e"
|
||||
integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==
|
||||
|
Loading…
Reference in New Issue
Block a user