Merge branch 'darwin-arm64-support' into darwin-arm64-support-test

This commit is contained in:
Daniel Sanchez 2021-04-21 17:01:11 +02:00
commit 10d394328f
61 changed files with 788 additions and 745 deletions

View File

@ -21,6 +21,6 @@ jobs:
path-to-signatures: 'signatures/version1/cla.json'
path-to-cla-document: 'https://github.com/gnosis/safe-react/blob/master/GNOSISCLA.md'
branch: 'cla-signatures'
allowlist: lukasschor,mikheevm,rmeissner,germartinez,fernandomg,Agupane,nicosampler,matextrem,gabitoesmiapodo,davidalbela,alongoni,Uxio0,dasanra,miguelmota,francovenica,tschubotz,luarx,giacomolicari,gnosis-info,bot*
allowlist: lukasschor,mikheevm,rmeissner,germartinez,fernandomg,Agupane,nicosampler,matextrem,gabitoesmiapodo,davidalbela,alongoni,Uxio0,dasanra,miguelmota,francovenica,tschubotz,luarx,giacomolicari,gnosis-info,bot*,katspaugh
empty-commit-flag: false
blockchain-storage-flag: false

View File

@ -161,9 +161,9 @@
"@gnosis.pm/safe-apps-sdk": "1.0.3",
"@gnosis.pm/safe-apps-sdk-v1": "npm:@gnosis.pm/safe-apps-sdk@0.4.2",
"@gnosis.pm/safe-contracts": "1.1.1-dev.2",
"@gnosis.pm/safe-react-components": "https://github.com/gnosis/safe-react-components.git#2e427ee",
"@gnosis.pm/safe-react-components": "https://github.com/gnosis/safe-react-components.git#b281238",
"@gnosis.pm/util-contracts": "2.0.6",
"@ledgerhq/hw-transport-node-hid-singleton": "5.45.0",
"@ledgerhq/hw-transport-node-hid-singleton": "5.49.0",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.11.0",
"@material-ui/lab": "4.0.0-alpha.57",
@ -175,13 +175,11 @@
"async-sema": "^3.1.0",
"axios": "0.21.1",
"bignumber.js": "9.0.1",
"bnc-onboard": "~1.20.0",
"bnc-onboard": "~1.22.0",
"classnames": "^2.2.6",
"concurrently": "^5.3.0",
"connected-react-router": "6.8.0",
"coveralls": "^3.1.0",
"currency-flags": "2.1.2",
"date-fns": "2.16.1",
"date-fns": "^2.20.2",
"detect-port": "^1.3.0",
"electron-is-dev": "^1.2.0",
"electron-log": "^4.3.0",
@ -211,13 +209,13 @@
"react": "16.13.1",
"react-device-detect": "^1.15.0",
"react-dom": "16.13.1",
"react-final-form": "^6.5.2",
"react-final-form": "^6.5.3",
"react-final-form-listeners": "^1.0.2",
"react-ga": "3.3.0",
"react-hot-loader": "4.13.0",
"react-intersection-observer": "^8.31.0",
"react-qr-reader": "^2.2.1",
"react-redux": "7.2.2",
"react-redux": "7.2.3",
"react-router-dom": "5.2.0",
"react-scripts": "^4.0.1",
"react-window": "^1.8.6",
@ -234,28 +232,30 @@
},
"devDependencies": {
"@rescripts/cli": "^0.0.16",
"@sentry/cli": "^1.63.1",
"@sentry/cli": "^1.64.0",
"@storybook/addon-actions": "^5.3.19",
"@storybook/addon-links": "^5.3.19",
"@storybook/addons": "^5.3.19",
"@storybook/preset-create-react-app": "^3.1.5",
"@storybook/react": "^5.3.19",
"@testing-library/jest-dom": "^5.11.6",
"@testing-library/react": "^11.2.2",
"@testing-library/jest-dom": "^5.11.10",
"@testing-library/react": "^11.2.6",
"@typechain/web3-v1": "^2.2.0",
"@types/history": "4.6.2",
"@types/jest": "^26.0.16",
"@types/jest": "^26.0.22",
"@types/lodash.get": "^4.4.6",
"@types/lodash.memoize": "^4.1.6",
"@types/node": "^14.14.30",
"@types/node": "^14.14.37",
"@types/react": "^16.14.5",
"@types/react-dom": "^16.9.9",
"@types/react-dom": "^16.9.12",
"@types/react-redux": "^7.1.11",
"@types/react-router-dom": "^5.1.6",
"@types/redux-actions": "^2.6.1",
"@types/styled-components": "^5.1.4",
"@typescript-eslint/eslint-plugin": "^4.17.0",
"@typescript-eslint/parser": "^4.17.0",
"@types/styled-components": "^5.1.9",
"@typescript-eslint/eslint-plugin": "^4.22.0",
"@typescript-eslint/parser": "^4.22.0",
"concurrently": "^6.0.0",
"coveralls": "^3.1.0",
"cross-env": "^7.0.3",
"dotenv": "^8.2.0",
"dotenv-expand": "^5.1.0",
@ -268,7 +268,6 @@
"eslint-plugin-jsx-a11y": "^6.3.1",
"eslint-plugin-prettier": "^3.1.4",
"eslint-plugin-react": "^7.21.5",
"eslint-plugin-sort-destructure-keys": "^1.3.5",
"husky": "~4.3.8",
"lint-staged": "^10.5.2",
"patch-package": "^6.4.6",
@ -277,6 +276,6 @@
"sass": "^1.32.0",
"typechain": "^4.0.0",
"typescript": "4.2.3",
"wait-on": "5.2.1"
"wait-on": "^5.3.0"
}
}

View File

@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="favicon.ico">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<title>Gnosis Safe Multisig</title>
<title>Gnosis Safe</title>
</head>
<style>
.safe-preloader-animation {

View File

@ -1,6 +1,19 @@
# Gnosis Safe Multisig
# Gnosis Safe
The most trusted platform to store digital assets on Ethereum
The most trusted platform to store digital assets on Ethereum. More info at [gnosis-safe.io](https://gnosis-safe.io/)
This repository contains the code for the frontend code hosted at [https://gnosis-safe.io/app/]
Besides Ethereum Mainnet, the following networks are supported:
- [Rinkeby Testnet](https://rinkeby.gnosis-safe.io/app/)
- [xDai](https://xdai.gnosis-safe.io/app/)
- [Energy Web Chain](https://ewc.gnosis-safe.io/app/)
- [Volta Testnet](https://volta.gnosis-safe.io/app/)
For technical information please refer to the [Gnosis Developer Portal](https://docs.gnosis.io/safe/).
For support requests, please open up a [bug issue](https://github.com/gnosis/safe-react/issues/new?template=bug-report.md) or reach out via [Discord](https://discordapp.com/invite/FPMRAwK).
## Getting Started
@ -132,17 +145,6 @@ Please read [CONTRIBUTING.md](https://gist.github.com/PurpleBooth/b24679402957c6
We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/gnosis/gnosis-team-safe/tags).
## Authors
- Germán Martínez([germartinez](https://github.com/germartinez))
- Mikhail Mikheev([mikheevm](https://github.com/mikheevm))
See the full list of [contributors](https://github.com/gnosis/gnosis-team-safe/contributors) who participated in this project.
## License
This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details
## Acknowledgments
* Thanks for Gnosis Team for providing the Safe contracts.

View File

@ -112,7 +112,7 @@ export const MobileNotSupported = ({ onClose }: Props): ReactElement => {
<Overlay>
<ModalApp>
<StyledCard>
<Text size="lg">The Safe Multisig web app is not optimized for mobile.</Text>
<Text size="lg">The Gnosis Safe web app is not optimized for mobile.</Text>
<Text size="lg">Get the mobile app for a better experience.</Text>
<Button size="md" color="primary" variant="contained">
<StyledLink target="_blank" href="https://gnosis-safe.io/#mobile" rel="noopener noreferrer">

View File

@ -44,7 +44,7 @@ const SidebarWrapper = styled.aside`
box-shadow: 0 2px 4px 0 rgba(40, 54, 61, 0.18);
`
const ContentWrapper = styled.section`
const ContentWrapper = styled.div`
width: 100%;
display: flex;
flex-direction: column;

View File

@ -1,8 +1,8 @@
import Onboard from 'bnc-onboard'
import React from 'react'
import React, { ReactElement } from 'react'
import Button from 'src/components/layout/Button'
import { getNetworkId } from 'src/config'
import { getNetworkId, getNetworkName } from 'src/config'
import { getWeb3, setWeb3 } from 'src/logic/wallets/getWeb3'
import { fetchProvider, removeProvider } from 'src/logic/wallets/store/actions'
import transactionDataCheck from 'src/logic/wallets/transactionDataCheck'
@ -10,6 +10,7 @@ import { getSupportedWallets } from 'src/logic/wallets/utils/walletList'
import { store } from 'src/store'
const networkId = getNetworkId()
const networkName = getNetworkName().toLowerCase()
let lastUsedAddress = ''
let providerName
@ -17,7 +18,8 @@ let providerName
const wallets = getSupportedWallets()
export const onboard = Onboard({
networkId: networkId,
networkId,
networkName,
subscriptions: {
wallet: (wallet) => {
if (wallet.provider) {
@ -42,7 +44,7 @@ export const onboard = Onboard({
},
},
walletSelect: {
description: 'Please select a wallet to connect to Gnosis Safe Multisig',
description: 'Please select a wallet to connect to Gnosis Safe',
wallets,
},
walletCheck: [
@ -72,7 +74,7 @@ export const onConnectButtonClick = async () => {
}
}
const ConnectButton = (props): React.ReactElement => (
const ConnectButton = (props): ReactElement => (
<Button color="primary" minWidth={240} onClick={onConnectButtonClick} variant="contained" {...props}>
Connect
</Button>

View File

@ -1,16 +0,0 @@
import CircularProgress from '@material-ui/core/CircularProgress'
import * as React from 'react'
import Page from 'src/components/layout/Page'
const centerStyle = {
margin: 'auto 0',
}
const Loader = () => (
<Page align="center">
<CircularProgress size={60} style={centerStyle} />
</Page>
)
export default Loader

View File

@ -11,6 +11,9 @@ import Row from 'src/components/layout/Row'
const StyledParagraph = styled(Paragraph)`
&& {
font-size: ${lg};
white-space: nowrap;
max-width: 370px;
overflow: hidden;
}
`
const IconImg = styled.img`
@ -57,7 +60,7 @@ const ModalTitle = ({ goBack, iconUrl, title, onClose }: Props): React.ReactElem
</GoBackWrapper>
)}
{iconUrl && <IconImg alt={title} src={iconUrl} />}
<StyledParagraph noMargin weight="bolder">
<StyledParagraph noMargin weight="bolder" title={title}>
{title}
</StyledParagraph>
</TitleWrapper>

View File

@ -1,4 +1,4 @@
import { theme as styledTheme } from '@gnosis.pm/safe-react-components'
import { theme as styledTheme, Loader } from '@gnosis.pm/safe-react-components'
import { MuiThemeProvider } from '@material-ui/core/styles'
import { ConnectedRouter } from 'connected-react-router'
import React from 'react'
@ -6,7 +6,7 @@ import { Provider } from 'react-redux'
import { ThemeProvider } from 'styled-components'
import * as Sentry from '@sentry/react'
import Loader from 'src/components/Loader'
import { LoadingContainer } from 'src/components/LoaderContainer'
import App from 'src/components/App'
import GlobalErrorBoundary from 'src/components/GlobalErrorBoundary'
import AppRoutes from 'src/routes'
@ -23,7 +23,14 @@ const Root = (): React.ReactElement => (
<MuiThemeProvider theme={theme}>
<ConnectedRouter history={history}>
<Sentry.ErrorBoundary fallback={GlobalErrorBoundary}>
<App>{wrapInSuspense(<AppRoutes />, <Loader />)}</App>
<App>
{wrapInSuspense(
<AppRoutes />,
<LoadingContainer>
<Loader size="md" />
</LoadingContainer>,
)}
</App>
</Sentry.ErrorBoundary>
</ConnectedRouter>
</MuiThemeProvider>

View File

@ -27,7 +27,7 @@ export const ScanQRWrapper = ({ handleScan }: Props): ReactElement => {
setQrModalOpen(false)
}
const onScanFinished = (value) => {
const onScanFinished = (value: string) => {
handleScan(value, closeQrModal)
}

View File

@ -1,4 +1,3 @@
import CircularProgress from '@material-ui/core/CircularProgress'
import IconButton from '@material-ui/core/IconButton'
import { makeStyles } from '@material-ui/core/styles'
import Close from '@material-ui/icons/Close'
@ -6,7 +5,6 @@ import * as React from 'react'
import QrReader from 'react-qr-reader'
import { styles } from './style'
import { checkWebcam } from './utils'
import Modal from 'src/components/Modal'
import Block from 'src/components/layout/Block'
@ -27,45 +25,39 @@ type Props = {
export const ScanQRModal = ({ isOpen, onClose, onScan }: Props): React.ReactElement => {
const classes = useStyles()
const [useWebcam, setUseWebcam] = useState<boolean | null>(null)
const [fileUploadModalOpen, setFileUploadModalOpen] = useState<boolean>(false)
const [error, setError] = useState<string | null>(null)
const [cameraBlocked, setCameraBlocked] = useState<boolean>(false)
const scannerRef: any = React.createRef()
const openImageDialog = React.useCallback(() => {
scannerRef.current.openImageDialog()
}, [scannerRef])
useEffect(() => {
checkWebcam(
() => {
setUseWebcam(true)
},
() => {
setUseWebcam(false)
},
)
}, [])
useEffect(() => {
if (useWebcam === false && !fileUploadModalOpen && !error) {
if (!fileUploadModalOpen && cameraBlocked && !error) {
setFileUploadModalOpen(true)
openImageDialog()
}
}, [useWebcam, openImageDialog, fileUploadModalOpen, setFileUploadModalOpen, error])
}, [cameraBlocked, openImageDialog, fileUploadModalOpen, setFileUploadModalOpen, error])
const onFileScannedResolve = (error: Error | null, successData: string | null) => {
if (error) {
console.error('QR code error', error)
if (error.name === 'NotAllowedError' || error.name === 'PermissionDismissedError') {
setCameraBlocked(true)
setFileUploadModalOpen(false)
} else {
setError('The QR could not be read')
}
return
}
const onFileScannedResolve = (error: string | null, successData: string | null) => {
if (successData) {
onScan(successData)
} else if (cameraBlocked) {
setError('The QR could not be read')
}
if (error) {
console.error('Error uploading file', error)
setError(`The QR could not be read`)
}
if (!useWebcam) {
setError(`The QR could not be read`)
}
setFileUploadModalOpen(false)
}
return (
@ -80,20 +72,19 @@ export const ScanQRModal = ({ isOpen, onClose, onScan }: Props): React.ReactElem
</Row>
<Hairline />
<Col className={classes.detailsContainer} layout="column" middle="xs">
{error}
{useWebcam === null ? (
<Block className={classes.loaderContainer} justify="center">
<CircularProgress />
{error && (
<Block padding="md" margin="md">
{error}
</Block>
) : (
<QrReader
legacyMode={!useWebcam}
onError={(err) => onFileScannedResolve(err, null)}
onScan={(data) => onFileScannedResolve(null, data)}
ref={scannerRef}
style={{ width: '400px', height: '400px' }}
/>
)}
<QrReader
legacyMode={cameraBlocked}
onError={(err: Error) => onFileScannedResolve(err, null)}
onScan={(data: string) => onFileScannedResolve(null, data)}
ref={scannerRef}
style={{ width: '400px', height: '400px' }}
facingMode="user"
/>
</Col>
<Hairline />
<Row align="center" className={classes.buttonRow}>
@ -105,7 +96,7 @@ export const ScanQRModal = ({ isOpen, onClose, onScan }: Props): React.ReactElem
color="primary"
minWidth={154}
onClick={() => {
setUseWebcam(false)
setCameraBlocked(true)
setError(null)
setFileUploadModalOpen(false)
}}

View File

@ -19,7 +19,7 @@ export const styles = createStyles({
},
detailsContainer: {
backgroundColor: background,
maxHeight: '420px',
maxHeight: '450px',
},
buttonRow: {
height: '84px',

View File

@ -1,18 +0,0 @@
const navigatorCp: any = navigator
navigatorCp.getMedia =
navigatorCp.getUserMedia || // use the proper vendor prefix
navigatorCp.webkitGetUserMedia ||
navigatorCp.mozGetUserMedia ||
navigatorCp.msGetUserMedia
export const checkWebcam = (success, err) =>
navigatorCp.getMedia(
{ video: true },
() => {
success()
},
() => {
err()
},
)

View File

@ -1,4 +1,4 @@
import CircularProgress from '@material-ui/core/CircularProgress'
import { Loader } from '@gnosis.pm/safe-react-components'
import Table from '@material-ui/core/Table'
import TableBody from '@material-ui/core/TableBody'
import TablePagination from '@material-ui/core/TablePagination'
@ -36,7 +36,7 @@ const styles = {
},
}
const FIXED_HEIGHT = 49
const FIXED_EMPTY_HEIGHT = 255
const backProps = {
'aria-label': 'Previous Page',
@ -101,8 +101,8 @@ class GnoTable extends React.Component<any, any> {
}))
}
getEmptyStyle = (emptyRows) => ({
height: FIXED_HEIGHT * emptyRows,
getEmptyStyle = () => ({
height: `calc(100vh - ${FIXED_EMPTY_HEIGHT}px)`,
borderTopRightRadius: sm,
borderTopLeftRadius: sm,
backgroundColor: 'white',
@ -155,7 +155,6 @@ class GnoTable extends React.Component<any, any> {
sortedData = sortedData.slice(page * displayRows, page * displayRows + displayRows)
}
const emptyRows = displayRows - Math.min(displayRows, data.size - page * displayRows)
const isEmpty = size === 0 && !disableLoadingOnEmptyTable
return (
@ -167,8 +166,8 @@ class GnoTable extends React.Component<any, any> {
</Table>
)}
{isEmpty && (
<Row className={classes.loader} style={this.getEmptyStyle(emptyRows + 1)}>
<CircularProgress size={60} />
<Row className={classes.loader} style={this.getEmptyStyle()}>
<Loader size="sm" />
</Row>
)}
{!disablePagination && (

View File

@ -17,6 +17,7 @@ interface Props {
weight?: string
onClick?: MouseEventHandler<HTMLParagraphElement>
style?: CSSProperties
title?: string
}
const Paragraph = (props: Props): ReactElement => {

View File

@ -1,5 +1,5 @@
import EtherLogo from 'src/config/assets/token_eth.svg'
import { EnvironmentSettings, ETHEREUM_NETWORK, NetworkConfig } from 'src/config/networks/network.d'
import { EnvironmentSettings, ETHEREUM_NETWORK, NetworkConfig, WALLETS } from 'src/config/networks/network.d'
const baseConfig: EnvironmentSettings = {
clientGatewayUrl: 'https://safe-client.rinkeby.staging.gnosisdev.com/v1',
@ -45,6 +45,7 @@ const rinkeby: NetworkConfig = {
logoUri: EtherLogo,
},
},
disabledWallets: [WALLETS.FORTMATIC],
}
export default rinkeby

View File

@ -45,7 +45,6 @@ const xDai: NetworkConfig = {
WALLETS.OPERA_TOUCH,
WALLETS.TORUS,
WALLETS.TRUST,
WALLETS.WALLET_CONNECT,
WALLETS.WALLET_LINK,
WALLETS.AUTHEREUM,
WALLETS.LATTICE,

View File

@ -2,7 +2,7 @@ import { List } from 'immutable'
import { Confirmation } from 'src/logic/safe/store/models/types/confirmation'
import { EMPTY_DATA } from 'src/logic/wallets/ethTransactions'
import semverSatisfies from 'semver/functions/satisfies'
import { SAFE_VERSION_FOR_OFFCHAIN_SIGNATURES } from './transactions/offchainSigner'
import { SAFE_VERSION_FOR_OFF_CHAIN_SIGNATURES } from './transactions/offchainSigner'
// Here we're checking that safe contract version is greater or equal 1.1.1, but
// theoretically EIP712 should also work for 1.0.0 contracts
@ -17,7 +17,7 @@ export const checkIfOffChainSignatureIsPossible = (
!isExecution &&
!isSmartContractWallet &&
!!safeVersion &&
semverSatisfies(safeVersion, SAFE_VERSION_FOR_OFFCHAIN_SIGNATURES)
semverSatisfies(safeVersion, SAFE_VERSION_FOR_OFF_CHAIN_SIGNATURES)
// https://docs.gnosis.io/safe/docs/contracts_signatures/#pre-validated-signatures
export const getPreValidatedSignatures = (from: string, initialString: string = EMPTY_DATA): string => {

View File

@ -9,7 +9,7 @@ import {
getApprovalTransaction,
getExecutionTransaction,
saveTxToHistory,
tryOffchainSigning,
tryOffChainSigning,
} from 'src/logic/safe/transactions'
import { estimateSafeTxGas } from 'src/logic/safe/transactions/gas'
import * as aboutToExecuteTx from 'src/logic/safe/utils/aboutToExecuteTx'
@ -118,7 +118,7 @@ export const createTransaction = (
try {
if (checkIfOffChainSignatureIsPossible(isExecution, smartContractWallet, safeVersion)) {
const signature = await tryOffchainSigning(safeTxHash, { ...txArgs, safeAddress }, hardwareWallet)
const signature = await tryOffChainSigning(safeTxHash, { ...txArgs, safeAddress }, hardwareWallet, safeVersion)
if (signature) {
dispatch(closeSnackbarAction({ key: beforeExecutionKey }))

View File

@ -1,5 +1,5 @@
import GnosisSafeSol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafe.json'
import { List, Set, Map } from 'immutable'
import { List } from 'immutable'
import { Action, Dispatch } from 'redux'
import { AbiItem } from 'web3-utils'
@ -87,9 +87,8 @@ export const buildSafe = async (
currentVersion: currentVersion ?? '',
needsUpdate,
featuresEnabled,
balances: localSafe?.balances || Map(),
balances: [],
latestIncomingTxBlock: 0,
activeTokens: Set(),
modules,
spendingLimits,
}

View File

@ -10,7 +10,7 @@ import {
getPreValidatedSignatures,
} from 'src/logic/safe/safeTxSigner'
import { getApprovalTransaction, getExecutionTransaction, saveTxToHistory } from 'src/logic/safe/transactions'
import { tryOffchainSigning } from 'src/logic/safe/transactions/offchainSigner'
import { tryOffChainSigning } from 'src/logic/safe/transactions/offchainSigner'
import * as aboutToExecuteTx from 'src/logic/safe/utils/aboutToExecuteTx'
import { getCurrentSafeVersion } from 'src/logic/safe/utils/safeVersion'
import { EMPTY_DATA } from 'src/logic/wallets/ethTransactions'
@ -111,7 +111,7 @@ export const processTransaction = ({
try {
if (checkIfOffChainSignatureIsPossible(isExecution, smartContractWallet, safeVersion)) {
const signature = await tryOffchainSigning(tx.safeTxHash, { ...txArgs, safeAddress }, hardwareWallet)
const signature = await tryOffChainSigning(tx.safeTxHash, { ...txArgs, safeAddress }, hardwareWallet, safeVersion)
if (signature) {
dispatch(closeSnackbarAction({ key: beforeExecutionKey }))

View File

@ -1,4 +1,4 @@
import { List, Map, Record, RecordOf, Set } from 'immutable'
import { List, Record, RecordOf } from 'immutable'
import { FEATURES } from 'src/config/networks/network.d'
import { BalanceRecord } from 'src/logic/tokens/store/actions/fetchSafeTokens'
@ -33,8 +33,7 @@ export type SafeRecordProps = {
owners: List<SafeOwner>
modules?: ModulePair[] | null
spendingLimits?: SpendingLimit[] | null
activeTokens: Set<string>
balances: Map<string, BalanceRecord>
balances: BalanceRecord[]
nonce: number
latestIncomingTxBlock: number
recurringUser?: boolean
@ -53,8 +52,7 @@ const makeSafe = Record<SafeRecordProps>({
owners: List([]),
modules: [],
spendingLimits: [],
activeTokens: Set(),
balances: Map(),
balances: [],
nonce: 0,
loadedViaUrl: false,
latestIncomingTxBlock: 0,

View File

@ -1,4 +1,4 @@
import { Map, Set, List } from 'immutable'
import { Map, List } from 'immutable'
import { Action, handleActions } from 'redux-actions'
import { ADD_SAFE_OWNER } from 'src/logic/safe/store/actions/addSafeOwner'
@ -25,14 +25,10 @@ export const buildSafe = (storedSafe: SafeRecordProps): SafeRecordProps => {
const names = storedSafe.owners.map((owner) => owner.name)
const addresses = storedSafe.owners.map((owner) => checksumAddress(owner.address))
const owners = buildOwnersFrom(Array.from(names), Array.from(addresses))
const activeTokens = Set(storedSafe.activeTokens)
const balances = Map(storedSafe.balances)
return {
...storedSafe,
owners,
balances,
activeTokens,
latestIncomingTxBlock: 0,
modules: null,
}

View File

@ -1,4 +1,4 @@
import { List, Set } from 'immutable'
import { List } from 'immutable'
import { matchPath, RouteComponentProps } from 'react-router-dom'
import { createSelector } from 'reselect'
import { SAFELIST_ADDRESS, SAFE_PARAM_ADDRESS } from 'src/routes/routes'
@ -9,6 +9,7 @@ import { AppReduxState } from 'src/store'
import { checksumAddress } from 'src/utils/checksumAddress'
import makeSafe, { SafeRecord, SafeRecordProps } from '../models/safe'
import { SafesMap } from 'src/routes/safe/store/reducer/types/safe'
import { BalanceRecord } from 'src/logic/tokens/store/actions/fetchSafeTokens'
const safesStateSelector = (state: AppReduxState) => state[SAFE_REDUCER_ID]
@ -65,14 +66,14 @@ export const safeSelector = createSelector(
},
)
export const safeActiveTokensSelector = createSelector(
export const safeBalancesSelector = createSelector(
safeSelector,
(safe): Set<string> => {
(safe): Array<BalanceRecord> => {
if (!safe) {
return Set()
return []
}
return safe.activeTokens
return safe.balances
},
)
@ -86,8 +87,6 @@ export const safeNameSelector = createSelector(safeSelector, safeFieldSelector('
export const safeEthBalanceSelector = createSelector(safeSelector, safeFieldSelector('ethBalance'))
export const safeBalancesSelector = createSelector(safeSelector, safeFieldSelector('balances'))
export const safeNeedsUpdateSelector = createSelector(safeSelector, safeFieldSelector('needsUpdate'))
export const safeCurrentVersionSelector = createSelector(safeSelector, safeFieldSelector('currentVersion'))
@ -117,18 +116,6 @@ export const safeOwnersAddressesListSelector = createSelector(
},
)
export const getActiveTokensAddressesForAllSafes = createSelector(safesListSelector, (safes) => {
const addresses = Set().withMutations((set) => {
safes.forEach((safe) => {
safe.activeTokens.forEach((tokenAddress) => {
set.add(tokenAddress)
})
})
})
return addresses
})
export const safeTotalFiatBalanceSelector = createSelector(safeSelector, (currentSafe) => {
return currentSafe?.totalFiatBalance
})

View File

@ -1,6 +1,8 @@
import semverSatisfies from 'semver/functions/satisfies'
import { METAMASK_REJECT_CONFIRM_TX_ERROR_CODE } from 'src/logic/safe/store/actions/createTransaction'
import { getEIP712Signer } from './EIP712Signer'
import { ethSigner } from './ethSigner'
import { METAMASK_REJECT_CONFIRM_TX_ERROR_CODE } from 'src/logic/safe/store/actions/createTransaction'
// 1. we try to sign via EIP-712 if user's wallet supports it
// 2. If not, try to use eth_sign (Safe version has to be >1.1.1)
@ -13,16 +15,31 @@ const SIGNERS = {
ETH_SIGN: ethSigner,
}
export const SAFE_VERSION_FOR_OFF_CHAIN_SIGNATURES = '>=1.0.0'
// hardware wallets support eth_sign only
const getSignersByWallet = (isHW) =>
isHW ? [SIGNERS.ETH_SIGN] : [SIGNERS.EIP712_V3, SIGNERS.EIP712_V4, SIGNERS.EIP712, SIGNERS.ETH_SIGN]
// eth_sign is only supported by safes >= 1.1.0
const getSupportedSigners = (isHW: boolean, safeVersion: string) => {
const safeSupportsEthSigner = semverSatisfies(safeVersion, '>=1.1.0')
export const SAFE_VERSION_FOR_OFFCHAIN_SIGNATURES = '>=1.1.1'
const signers = isHW ? [] : [SIGNERS.EIP712_V3, SIGNERS.EIP712_V4, SIGNERS.EIP712]
export const tryOffchainSigning = async (safeTxHash: string, txArgs, isHW: boolean): Promise<string> => {
if (safeSupportsEthSigner) {
signers.push(SIGNERS.ETH_SIGN)
}
return signers
}
export const tryOffChainSigning = async (
safeTxHash: string,
txArgs,
isHW: boolean,
safeVersion: string,
): Promise<string | undefined> => {
let signature
const signerByWallet = getSignersByWallet(isHW)
const signerByWallet = getSupportedSigners(isHW, safeVersion)
for (const signingFunc of signerByWallet) {
try {
signature = await signingFunc({ ...txArgs, safeTxHash })

View File

@ -1,5 +1,5 @@
import { SafeRecordProps } from 'src/logic/safe/store/models/safe'
import { List, Set, Map } from 'immutable'
import { List } from 'immutable'
import { shouldSafeStoreBeUpdated } from 'src/logic/safe/utils/shouldSafeStoreBeUpdated'
const getMockedOldSafe = ({
@ -7,7 +7,6 @@ const getMockedOldSafe = ({
needsUpdate,
balances,
recurringUser,
activeTokens,
owners,
featuresEnabled,
currentVersion,
@ -38,13 +37,10 @@ const getMockedOldSafe = ({
owners: owners || List([owner1, owner2]),
modules: modules || [],
spendingLimits: spendingLimits || [],
activeTokens: activeTokens || Set([mockedActiveTokenAddress1, mockedActiveTokenAddress2]),
balances:
balances ||
Map({
[mockedActiveTokenAddress1]: { tokenBalance: '100' },
[mockedActiveTokenAddress2]: { tokenBalance: '10' },
}),
balances: balances || [
{ tokenAddress: mockedActiveTokenAddress1, tokenBalance: '100' },
{ tokenAddress: mockedActiveTokenAddress2, tokenBalance: '10' },
],
nonce: nonce || 2,
latestIncomingTxBlock: latestIncomingTxBlock || 1,
recurringUser: recurringUser || false,
@ -177,34 +173,15 @@ describe('shouldSafeStoreBeUpdated', () => {
// Then
expect(expectedResult).toEqual(true)
})
it(`Given an old activeTokens list and a new activeTokens list for the safe, should return true`, () => {
// given
const mockedActiveTokenAddress1 = '0x36591cd3DA96b21Ac9ca54cFaf80fe45107294F1'
const mockedActiveTokenAddress2 = '0x92aF97cbF10742dD2527ffaBA70e34C03CFFC2c1'
const oldActiveTokens = Set([mockedActiveTokenAddress1, mockedActiveTokenAddress2])
const newActiveTokens = Set([mockedActiveTokenAddress1])
const oldSafe = getMockedOldSafe({ activeTokens: oldActiveTokens })
const newSafeProps: Partial<SafeRecordProps> = {
activeTokens: newActiveTokens,
}
// When
const expectedResult = shouldSafeStoreBeUpdated(newSafeProps, oldSafe)
// Then
expect(expectedResult).toEqual(true)
})
it(`Given an old balances list and a new balances list for the safe, should return true`, () => {
// given
const mockedActiveTokenAddress1 = '0x36591cd3DA96b21Ac9ca54cFaf80fe45107294F1'
const mockedActiveTokenAddress2 = '0x92aF97cbF10742dD2527ffaBA70e34C03CFFC2c1'
const oldBalances = Map({
[mockedActiveTokenAddress1]: { tokenBalance: '100' },
[mockedActiveTokenAddress2]: { tokenBalance: '100' },
})
const newBalances = Map({
[mockedActiveTokenAddress1]: { tokenBalance: '100' },
})
const oldBalances = [
{ tokenAddress: mockedActiveTokenAddress1, tokenBalance: '100' },
{ tokenAddress: mockedActiveTokenAddress2, tokenBalance: '100' },
]
const newBalances = [{ tokenAddress: mockedActiveTokenAddress1, tokenBalance: '100' }]
const oldSafe = getMockedOldSafe({ balances: oldBalances })
const newSafeProps: Partial<SafeRecordProps> = {
balances: newBalances,

View File

@ -1,50 +1,46 @@
import { backOff } from 'exponential-backoff'
import { List, Map } from 'immutable'
import { List } from 'immutable'
import { Dispatch } from 'redux'
import { fetchTokenCurrenciesBalances, TokenBalance } from 'src/logic/safe/api/fetchTokenCurrenciesBalances'
import { addTokens } from 'src/logic/tokens/store/actions/addTokens'
import { makeToken, Token } from 'src/logic/tokens/store/model/token'
import { TokenState } from 'src/logic/tokens/store/reducer/tokens'
import updateSafe from 'src/logic/safe/store/actions/updateSafe'
import { AppReduxState } from 'src/store'
import { humanReadableValue } from 'src/logic/tokens/utils/humanReadableValue'
import { safeActiveTokensSelector, safeSelector } from 'src/logic/safe/store/selectors'
import { tokensSelector } from 'src/logic/tokens/store/selectors'
import { safeSelector } from 'src/logic/safe/store/selectors'
import BigNumber from 'bignumber.js'
import { currentCurrencySelector } from 'src/logic/currencyValues/store/selectors'
import { ZERO_ADDRESS, sameAddress } from 'src/logic/wallets/ethAddresses'
export type BalanceRecord = {
tokenAddress?: string
tokenBalance: string
fiatBalance?: string
}
interface ExtractedData {
balances: Map<string, BalanceRecord>
balances: Array<BalanceRecord>
ethBalance: string
tokens: List<Token>
}
const extractDataFromResult = (currentTokens: TokenState) => (
const extractDataFromResult = (
acc: ExtractedData,
{ balance, fiatBalance, tokenInfo }: TokenBalance,
): ExtractedData => {
const { address, decimals } = tokenInfo
acc.balances = acc.balances.merge({
[address]: {
fiatBalance,
tokenBalance: humanReadableValue(balance, Number(decimals)),
},
acc.balances.push({
tokenAddress: address,
fiatBalance,
tokenBalance: humanReadableValue(balance, Number(decimals)),
})
// Extract network token balance from backend balances
if (sameAddress(address, ZERO_ADDRESS)) {
acc.ethBalance = humanReadableValue(balance, Number(decimals))
}
if (currentTokens && !currentTokens.get(address)) {
} else {
acc.tokens = acc.tokens.push(makeToken({ ...tokenInfo }))
}
@ -58,7 +54,6 @@ export const fetchSafeTokens = (safeAddress: string, currencySelected?: string)
try {
const state = getState()
const safe = safeSelector(state)
const currentTokens = tokensSelector(state)
if (!safe) {
return
@ -68,24 +63,19 @@ export const fetchSafeTokens = (safeAddress: string, currencySelected?: string)
const tokenCurrenciesBalances = await backOff(() =>
fetchTokenCurrenciesBalances({ safeAddress, selectedCurrency: currencySelected ?? selectedCurrency }),
)
const alreadyActiveTokens = safeActiveTokensSelector(state)
const { balances, ethBalance, tokens } = tokenCurrenciesBalances.items.reduce<ExtractedData>(
extractDataFromResult(currentTokens),
extractDataFromResult,
{
balances: Map(),
balances: [],
ethBalance: '0',
tokens: List(),
},
)
// need to persist those already active tokens, despite its balances
const activeTokens = alreadyActiveTokens.union(balances.keySeq().toSet())
dispatch(
updateSafe({
address: safeAddress,
activeTokens,
balances,
ethBalance,
totalFiatBalance: new BigNumber(tokenCurrenciesBalances.fiatTotal).toFixed(2),

View File

@ -4,10 +4,11 @@ import { Redirect, Route, Switch, useLocation, useRouteMatch } from 'react-route
import { LOAD_ADDRESS, OPEN_ADDRESS, SAFELIST_ADDRESS, SAFE_PARAM_ADDRESS, WELCOME_ADDRESS } from './routes'
import Loader from 'src/components/Loader'
import { Loader } from '@gnosis.pm/safe-react-components'
import { defaultSafeSelector } from 'src/logic/safe/store/selectors'
import { useAnalytics } from 'src/utils/googleAnalytics'
import { DEFAULT_SAFE_INITIAL_STATE } from 'src/logic/safe/store/reducer/safe'
import { LoadingContainer } from 'src/components/LoaderContainer'
const Welcome = React.lazy(() => import('./welcome/container'))
@ -60,7 +61,11 @@ const Routes = (): React.ReactElement => {
}
if (defaultSafe === DEFAULT_SAFE_INITIAL_STATE) {
return <Loader />
return (
<LoadingContainer>
<Loader size="md" />
</LoadingContainer>
)
}
if (defaultSafe) {

View File

@ -80,7 +80,7 @@ const DetailsForm = ({ errors, form }: DetailsFormProps): React.ReactElement =>
<>
<Block margin="md">
<Paragraph color="primary" noMargin size="md">
You are about to load an existing Gnosis Safe. First, choose a name and enter the Safe address. The name is
You are about to add an existing Gnosis Safe. First, choose a name and enter the Safe address. The name is
only stored locally and will never be shared with Gnosis or any third parties.
<br />
Your connected wallet does not have to be the owner of this Safe. In this case, the interface will provide you

View File

@ -15,7 +15,7 @@ import { secondary, sm } from 'src/theme/variables'
import { LoadFormValues } from '../container/Load'
const steps = ['Name and address', 'Owners', 'Review']
const buttonLabels = ['Next', 'Review', 'Load']
const buttonLabels = ['Next', 'Review', 'Add']
const iconStyle = {
color: secondary,
@ -48,7 +48,7 @@ const Layout = ({ network, onLoadSafeSubmit, provider, userAddress }: LayoutProp
<IconButton disableRipple onClick={back} style={iconStyle}>
<ChevronLeft />
</IconButton>
<Heading tag="h2">Load existing Safe</Heading>
<Heading tag="h2">Add existing Safe</Heading>
</Row>
<Stepper<LoadFormValues>
buttonLabels={buttonLabels}

View File

@ -66,7 +66,7 @@ const Load = (): React.ReactElement => {
let safeAddress = values[FIELD_LOAD_ADDRESS]
// TODO: review this check. It doesn't seems to be necessary at this point
if (!safeAddress) {
console.error('failed to load Safe address', JSON.stringify(values))
console.error('failed to add Safe address', JSON.stringify(values))
return
}

View File

@ -117,7 +117,7 @@ export const Layout = (props: LayoutProps): React.ReactElement => {
<ChevronLeft />
</IconButton>
<Heading tag="h2" testId="create-safe-form-title">
Create New Safe
Create new Safe
</Heading>
</Row>
<Stepper

View File

@ -44,8 +44,8 @@ const SafeNameForm = ({ safeName }: { safeName: string }): React.ReactElement =>
<>
<Block margin="lg">
<Paragraph color="primary" noMargin size="lg">
You are about to create a new Gnosis Safe wallet with one or more owners. First, let&apos;s give your new
wallet a name. This name is only stored locally and will never be shared with Gnosis or any third parties.
You are about to create a new Safe with one or more owners. First, let&apos;s give your new Safe a name. This
name is only stored locally and will never be shared with Gnosis or any third parties.
</Paragraph>
</Block>
<Block className={classes.root} margin="lg">

View File

@ -1,5 +1,5 @@
import { isAppManifestValid } from '../utils'
import { SafeApp, SAFE_APP_FETCH_STATUS } from '../types.d'
import { SafeApp } from '../types.d'
describe('SafeApp manifest', () => {
it('It should return true given a manifest with mandatory values supplied', async () => {

View File

@ -0,0 +1,21 @@
import axios from 'axios'
import { SAFE_APPS_LIST_URL } from 'src/utils/constants'
export type TokenListResult = {
name: string
timestamp: string
apps: AppData[]
}
export type AppData = {
url: string
name?: string
disabled?: boolean
description?: string
networks: number[]
}
export const fetchSafeAppsList = async (): Promise<TokenListResult> => {
return axios.get(SAFE_APPS_LIST_URL).then(({ data }) => data)
}

View File

@ -41,7 +41,7 @@ const AppDocsInfo = styled.div`
}
`
export interface AddAppFormValues {
interface AddAppFormValues {
appUrl: string
agreementAccepted: boolean
}

View File

@ -1,18 +1,8 @@
import React, { useState, useRef, useCallback, useEffect } from 'react'
import styled from 'styled-components'
import {
FixedIcon,
Loader,
Title,
Text,
Card,
GenericModal,
ModalFooterConfirmation,
Menu,
ButtonLink,
} from '@gnosis.pm/safe-react-components'
import { FixedIcon, Loader, Title, Card } from '@gnosis.pm/safe-react-components'
import { MethodToResponse, RPCPayload } from '@gnosis.pm/safe-apps-sdk'
import { useHistory, useRouteMatch } from 'react-router-dom'
import { useHistory } from 'react-router-dom'
import { useSelector } from 'react-redux'
import { INTERFACE_MESSAGES, Transaction, RequestId, LowercaseNetworks } from '@gnosis.pm/safe-apps-sdk-v1'
@ -26,8 +16,7 @@ import { getNetworkName, getTxServiceUrl } from 'src/config'
import { SAFELIST_ADDRESS } from 'src/routes/routes'
import { isSameURL } from 'src/utils/url'
import { useAnalytics, SAFE_NAVIGATION_EVENT } from 'src/utils/googleAnalytics'
import { loadFromStorage, saveToStorage } from 'src/utils/storage'
import { staticAppsList } from 'src/routes/safe/components/Apps/utils'
import { useAppList } from '../hooks/useAppList'
import { LoadingContainer } from 'src/components/LoaderContainer/index'
import { TIMEOUT } from 'src/utils/constants'
import { web3ReadOnly } from 'src/logic/wallets/getWeb3'
@ -36,8 +25,8 @@ import { ConfirmTxModal } from '../components/ConfirmTxModal'
import { useIframeMessageHandler } from '../hooks/useIframeMessageHandler'
import { useLegalConsent } from '../hooks/useLegalConsent'
import LegalDisclaimer from './LegalDisclaimer'
import { APPS_STORAGE_KEY, getAppInfoFromUrl } from '../utils'
import { SafeApp, StoredSafeApp } from '../types.d'
import { getAppInfoFromUrl } from '../utils'
import { SafeApp } from '../types.d'
import { useAppCommunicator } from '../communicator'
const OwnerDisclaimer = styled.div`
@ -51,12 +40,14 @@ const OwnerDisclaimer = styled.div`
const AppWrapper = styled.div`
display: flex;
flex-direction: column;
height: 100%;
height: calc(100% + 59px);
margin: 0 -16px;
`
const StyledCard = styled(Card)`
flex-grow: 1;
padding: 0;
border-radius: 0;
`
const StyledIframe = styled.iframe<{ isLoading: boolean }>`
@ -67,10 +58,6 @@ const StyledIframe = styled.iframe<{ isLoading: boolean }>`
display: ${({ isLoading }) => (isLoading ? 'none' : 'block')};
`
const Breadcrumb = styled.div`
height: 51px;
`
export type TransactionParams = {
safeTxGas?: number
}
@ -103,8 +90,7 @@ const AppFrame = ({ appUrl }: Props): React.ReactElement => {
const { trackEvent } = useAnalytics()
const history = useHistory()
const { consentReceived, onConsentReceipt } = useLegalConsent()
const matchSafeWithAddress = useRouteMatch<{ safeAddress: string }>({ path: `${SAFELIST_ADDRESS}/:safeAddress` })
const { staticAppsList } = useAppList()
const iframeRef = useRef<HTMLIFrameElement>(null)
const [confirmTransactionModal, setConfirmTransactionModal] = useState<ConfirmTransactionModalState>(
@ -112,8 +98,6 @@ const AppFrame = ({ appUrl }: Props): React.ReactElement => {
)
const [appIsLoading, setAppIsLoading] = useState<boolean>(true)
const [safeApp, setSafeApp] = useState<SafeApp | undefined>()
const [isRemoveModalOpen, setIsRemoveModalOpen] = useState(false)
const [isAppDeletable, setIsAppDeletable] = useState<boolean | undefined>()
const redirectToBalance = () => history.push(`${SAFELIST_ADDRESS}/${safeAddress}/balances`)
const timer = useRef<number>()
@ -246,30 +230,16 @@ const AppFrame = ({ appUrl }: Props): React.ReactElement => {
communicator?.send('Transaction was rejected', confirmTransactionModal.requestId, true)
}
const openRemoveModal = () => setIsRemoveModalOpen(true)
const closeRemoveModal = () => setIsRemoveModalOpen(false)
const removeApp = async () => {
const persistedAppList = (await loadFromStorage<StoredSafeApp[]>(APPS_STORAGE_KEY)) || []
const filteredList = persistedAppList.filter((a) => a.url !== safeApp?.url)
saveToStorage(APPS_STORAGE_KEY, filteredList)
const goToApp = `${matchSafeWithAddress?.url}/apps`
history.push(goToApp)
}
useEffect(() => {
const loadApp = async () => {
const app = await getAppInfoFromUrl(appUrl)
const existsStaticApp = staticAppsList.some((staticApp) => staticApp.url === app.url)
setIsAppDeletable(!existsStaticApp)
setSafeApp(app)
}
loadApp()
}, [appUrl])
if (staticAppsList.length) {
loadApp()
}
}, [appUrl, staticAppsList])
//track GA
useEffect(() => {
@ -305,21 +275,12 @@ const AppFrame = ({ appUrl }: Props): React.ReactElement => {
return (
<AppWrapper>
<Menu>
<Breadcrumb />
{isAppDeletable && (
<ButtonLink color="error" iconType="delete" onClick={openRemoveModal}>
Remove app
</ButtonLink>
)}
</Menu>
<StyledCard>
{appIsLoading && (
<LoadingContainer style={{ flexDirection: 'column' }}>
{appTimeout && (
<Title size="xs">
The safe-app is taking longer than usual to load. There might be a problem with the safe-app provider.
The safe app is taking longer than usual to load. There might be a problem with the app provider.
</Title>
)}
<Loader size="md" />
@ -337,26 +298,6 @@ const AppFrame = ({ appUrl }: Props): React.ReactElement => {
/>
</StyledCard>
{isRemoveModalOpen && (
<GenericModal
title={
<Title size="sm" withoutMargin>
Remove app
</Title>
}
body={<Text size="md">This action will remove {safeApp.name} from the interface</Text>}
footer={
<ModalFooterConfirmation
cancelText="Cancel"
handleCancel={closeRemoveModal}
handleOk={removeApp}
okText="Remove"
/>
}
onClose={closeRemoveModal}
/>
)}
<ConfirmTxModal
isOpen={confirmTransactionModal.isOpen}
app={safeApp as SafeApp}

View File

@ -1,7 +1,16 @@
import React, { useState } from 'react'
import styled, { css } from 'styled-components'
import { useSelector } from 'react-redux'
import { GenericModal, IconText, Loader, Menu } from '@gnosis.pm/safe-react-components'
import {
GenericModal,
IconText,
Loader,
Menu,
Icon,
ModalFooterConfirmation,
Text,
} from '@gnosis.pm/safe-react-components'
import IconButton from '@material-ui/core/IconButton'
import { safeParamAddressFromStateSelector } from 'src/logic/safe/store/selectors'
import AppCard from 'src/routes/safe/components/Apps/components/AppCard'
@ -12,6 +21,7 @@ import { SAFELIST_ADDRESS } from 'src/routes/routes'
import { useAppList } from '../hooks/useAppList'
import { SAFE_APP_FETCH_STATUS, SafeApp } from '../types.d'
import AddAppForm from './AddAppForm'
import { AppData } from '../api/fetchSafeAppsList'
const Wrapper = styled.div`
height: 100%;
@ -56,18 +66,41 @@ const Breadcrumb = styled.div`
height: 51px;
`
const IconBtn = styled(IconButton)`
position: absolute;
top: 10px;
right: 10px;
z-index: 10;
padding: 5px;
opacity: 0;
transition: opacity 0.2s ease-in-out;
`
const AppContainer = styled.div`
position: relative;
&:hover {
${IconBtn} {
opacity: 1;
}
}
`
const isAppLoading = (app: SafeApp) => SAFE_APP_FETCH_STATUS.LOADING === app.fetchStatus
const isCustomApp = (appUrl: string, staticAppsList: AppData[]) => !staticAppsList.some(({ url }) => url === appUrl)
const AppsList = (): React.ReactElement => {
const matchSafeWithAddress = useRouteMatch<{ safeAddress: string }>({ path: `${SAFELIST_ADDRESS}/:safeAddress` })
const safeAddress = useSelector(safeParamAddressFromStateSelector)
const { appList } = useAppList()
const { appList, removeApp, staticAppsList } = useAppList()
const [isAddAppModalOpen, setIsAddAppModalOpen] = useState<boolean>(false)
const [appToRemove, setAppToRemove] = useState<SafeApp | null>(null)
const openAddAppModal = () => setIsAddAppModalOpen(true)
const closeAddAppModal = () => setIsAddAppModalOpen(false)
const isAppLoading = (app: SafeApp) => SAFE_APP_FETCH_STATUS.LOADING === app.fetchStatus
if (!appList.length || !safeAddress) {
return (
<LoadingContainer>
@ -90,9 +123,23 @@ const AppsList = (): React.ReactElement => {
{appList
.filter((a) => a.fetchStatus !== SAFE_APP_FETCH_STATUS.ERROR)
.map((a) => (
<StyledLink key={a.url} to={`${matchSafeWithAddress?.url}/apps?appUrl=${encodeURI(a.url)}`}>
<AppCard isLoading={isAppLoading(a)} iconUrl={a.iconUrl} name={a.name} description={a.description} />
</StyledLink>
<AppContainer key={a.url}>
<StyledLink key={a.url} to={`${matchSafeWithAddress?.url}/apps?appUrl=${encodeURI(a.url)}`}>
<AppCard isLoading={isAppLoading(a)} iconUrl={a.iconUrl} name={a.name} description={a.description} />
</StyledLink>
{isCustomApp(a.url, staticAppsList) && (
<IconBtn
title="Remove"
onClick={(e) => {
e.stopPropagation()
setAppToRemove(a)
}}
>
<Icon size="sm" type="delete" color="error" />
</IconBtn>
)}
</AppContainer>
))}
</CardsWrapper>
@ -112,6 +159,25 @@ const AppsList = (): React.ReactElement => {
onClose={closeAddAppModal}
/>
)}
{appToRemove && (
<GenericModal
title="Remove app"
body={<Text size="md">This action will remove {appToRemove.name} from the interface</Text>}
footer={
<ModalFooterConfirmation
cancelText="Cancel"
handleCancel={() => setAppToRemove(null)}
handleOk={() => {
removeApp(appToRemove.url)
setAppToRemove(null)
}}
okText="Remove"
/>
}
onClose={() => setAppToRemove(null)}
/>
)}
</Wrapper>
)
}

View File

@ -1,15 +1,30 @@
import { useState, useEffect } from 'react'
import { loadFromStorage } from 'src/utils/storage'
import { APPS_STORAGE_KEY, getAppInfoFromUrl, getEmptySafeApp, staticAppsList } from '../utils'
import { useState, useEffect, useCallback } from 'react'
import { loadFromStorage, saveToStorage } from 'src/utils/storage'
import { APPS_STORAGE_KEY, getAppInfoFromUrl, getAppsList, getEmptySafeApp } from '../utils'
import { AppData } from '../api/fetchSafeAppsList'
import { SafeApp, StoredSafeApp, SAFE_APP_FETCH_STATUS } from '../types.d'
import { getNetworkId } from 'src/config'
type UseAppListReturnType = {
appList: SafeApp[]
removeApp: (appUrl: string) => void
staticAppsList: AppData[]
}
const useAppList = (): UseAppListReturnType => {
const [appList, setAppList] = useState<SafeApp[]>([])
const [staticAppsList, setStaticAppsList] = useState<AppData[]>([])
useEffect(() => {
const loadAppsList = async () => {
const remoteAppsList = await getAppsList()
setStaticAppsList(remoteAppsList)
}
if (!staticAppsList.length) {
loadAppsList()
}
}, [staticAppsList])
// Load apps list
// for each URL we return a mocked safe-app with a loading status
@ -42,21 +57,40 @@ const useAppList = (): UseAppListReturnType => {
.filter((app) => (!app.networks ? true : app.networks.includes(getNetworkId())))
.map((app) => ({
...getEmptySafeApp(),
...app,
url: app.url.trim(),
}))
setAppList(apps)
apps.forEach((app) => getAppInfoFromUrl(app.url).then(fetchAppCallback))
apps.forEach((app) => {
if (!app.name || app.name === 'unknown') {
// We are using legacy mode, we have to fetch info from manifest
getAppInfoFromUrl(app.url).then(fetchAppCallback)
} else {
// We already have manifest information so we directly add the app
fetchAppCallback(app)
}
})
}
if (!appList.length) {
loadApps()
}
}, [appList])
loadApps()
}, [staticAppsList])
const removeApp = useCallback((appUrl: string): void => {
setAppList((list) => {
const newList = list.filter(({ url }) => url !== appUrl)
const persistedAppList = newList.map(({ url, disabled }) => ({ url, disabled }))
saveToStorage(APPS_STORAGE_KEY, persistedAppList)
return newList
})
}, [])
return {
appList,
staticAppsList,
removeApp,
}
}

View File

@ -6,6 +6,7 @@ import { SafeApp, SAFE_APP_FETCH_STATUS } from './types.d'
import { getContentFromENS } from 'src/logic/wallets/getWeb3'
import appsIconSvg from 'src/assets/icons/apps.svg'
import { ETHEREUM_NETWORK } from 'src/config/networks/network.d'
import { AppData, fetchSafeAppsList } from './api/fetchSafeAppsList'
export const APPS_STORAGE_KEY = 'APPS_STORAGE_KEY'
@ -34,6 +35,12 @@ export const staticAppsList: Array<StaticAppInfo> = [
disabled: false,
networks: [ETHEREUM_NETWORK.MAINNET],
},
// Aave v2
{
url: `https://app.aave.com/`,
disabled: false,
networks: [ETHEREUM_NETWORK.MAINNET],
},
//Balancer Exchange
{
url: `${process.env.REACT_APP_IPFS_GATEWAY}/QmRb2VfPVYBrv6gi2zDywgVgTg3A19ZCRMqwL13Ez5f5AS`,
@ -61,10 +68,22 @@ export const staticAppsList: Array<StaticAppInfo> = [
},
// dHedge
{
url: `${process.env.REACT_APP_IPFS_GATEWAY}/QmaiemnumMaaK9wE1pbMfm3YSBUpcFNgDh3Bf6VZCZq57Q`,
url: `https://app.dhedge.org/`,
disabled: false,
networks: [ETHEREUM_NETWORK.MAINNET],
},
// ENS
{
url: `https://app.ens.domains/`,
disabled: false,
networks: [ETHEREUM_NETWORK.MAINNET, ETHEREUM_NETWORK.RINKEBY],
},
// Gnosis Starter
{
url: `${process.env.REACT_APP_IPFS_GATEWAY}/QmdCwUutYH8GXXNgTShB4cKJ8YJq4PqZ55QxMznKc9DbeS`,
disabled: false,
networks: [ETHEREUM_NETWORK.MAINNET, ETHEREUM_NETWORK.RINKEBY],
},
// Idle
{
url: `${process.env.REACT_APP_IPFS_GATEWAY}/QmTvrLwJtyjG8QFHgvqdPhcV5DBMQ7oZceSU4uvPw9vQaj`,
@ -77,6 +96,12 @@ export const staticAppsList: Array<StaticAppInfo> = [
disabled: false,
networks: [ETHEREUM_NETWORK.MAINNET],
},
// Liquity
{
url: `${process.env.REACT_APP_IPFS_GATEWAY}/QmYzTAH6Nzexu35tbWmhVrLYwWj9MdbD1iECejgaGHFk8P`,
disabled: false,
networks: [ETHEREUM_NETWORK.MAINNET, ETHEREUM_NETWORK.RINKEBY],
},
// Mushrooms finance
{
url: `${process.env.REACT_APP_IPFS_GATEWAY}/QmT96aES2YA9BssByc6DVizQDkofmKRErs8gJyqWipjyS8`,
@ -151,6 +176,17 @@ export const staticAppsList: Array<StaticAppInfo> = [
},
]
export const getAppsList = async (): Promise<AppData[]> => {
let result
try {
result = await fetchSafeAppsList()
} catch (error) {
console.error('Could not fetch remote apps list', error)
}
return result?.apps && result?.apps.length ? result.apps : staticAppsList
}
export const getAppInfoFromOrigin = (origin: string): { url: string; name: string } | null => {
try {
return JSON.parse(origin)

View File

@ -77,7 +77,7 @@ const Coins = (props: Props): React.ReactElement => {
const columns = generateColumns()
const autoColumns = columns.filter((c) => !c.custom)
const selectedCurrency = useSelector(currentCurrencySelector)
const activeTokens = useSelector(extendedSafeTokensSelector)
const safeTokens = useSelector(extendedSafeTokensSelector)
const granted = useSelector(grantedSelector)
const { trackEvent } = useAnalytics()
@ -85,22 +85,14 @@ const Coins = (props: Props): React.ReactElement => {
trackEvent({ category: SAFE_NAVIGATION_EVENT, action: 'Coins' })
}, [trackEvent])
const filteredData: List<BalanceData> = useMemo(() => getBalanceData(activeTokens, selectedCurrency), [
activeTokens,
const filteredData: List<BalanceData> = useMemo(() => getBalanceData(safeTokens, selectedCurrency), [
safeTokens,
selectedCurrency,
])
return (
<TableContainer>
<Table
columns={columns}
data={filteredData}
defaultFixed
defaultOrderBy={BALANCE_TABLE_ASSET_ID}
defaultRowsPerPage={100}
label="Balances"
size={filteredData.size}
>
<Table columns={columns} data={filteredData} defaultRowsPerPage={100} label="Balances" size={filteredData.size}>
{(sortedData) =>
sortedData.map((row, index) => (
<TableRow className={classes.hide} data-testid={BALANCE_ROW_TEST_ID} key={index} tabIndex={-1}>

View File

@ -1,4 +1,4 @@
import CircularProgress from '@material-ui/core/CircularProgress'
import { Loader } from '@gnosis.pm/safe-react-components'
import { makeStyles } from '@material-ui/core/styles'
import React, { Suspense, useEffect, useState } from 'react'
@ -116,7 +116,7 @@ const SendModal = ({
<Suspense
fallback={
<div className={classes.loaderStyle}>
<CircularProgress size={40} />
<Loader size="md" />
</div>
}
>

View File

@ -1,6 +1,4 @@
import { List } from 'immutable'
import { getNetworkInfo } from 'src/config'
import { FIXED } from 'src/components/Table/sorting'
import { formatAmountInUsFormat } from 'src/logic/tokens/utils/formatAmount'
import { TableColumn } from 'src/components/Table/types.d'
import { Token } from 'src/logic/tokens/store/model/token'
@ -20,14 +18,12 @@ export interface BalanceData {
assetOrder: string
balance: string
balanceOrder: number
fixed: boolean
value: string
valueOrder: number
}
export const getBalanceData = (activeTokens: List<Token>, currencySelected?: string): List<BalanceData> => {
const { nativeCoin } = getNetworkInfo()
return activeTokens.map((token) => {
export const getBalanceData = (safeTokens: List<Token>, currencySelected?: string): List<BalanceData> => {
return safeTokens.map((token) => {
const { tokenBalance, fiatBalance } = token.balance
return {
@ -40,7 +36,6 @@ export const getBalanceData = (activeTokens: List<Token>, currencySelected?: str
assetOrder: token.name,
[BALANCE_TABLE_BALANCE_ID]: `${formatAmountInUsFormat(tokenBalance?.toString() || '0')} ${token.symbol}`,
balanceOrder: Number(tokenBalance),
[FIXED]: token.symbol === nativeCoin.symbol,
[BALANCE_TABLE_VALUE_ID]: getTokenPriceInCurrency(fiatBalance || '0', currencySelected),
valueOrder: Number(tokenBalance),
}

View File

@ -1,29 +0,0 @@
import Badge from '@material-ui/core/Badge'
import React from 'react'
import { useSelector } from 'react-redux'
import { SettingsIcon } from 'src/routes/safe/components/assets/SettingsIcon'
import { grantedSelector } from 'src/routes/safe/container/selector'
import { safeNeedsUpdateSelector } from 'src/logic/safe/store/selectors'
const SettingsTab = () => {
const needsUpdate = useSelector(safeNeedsUpdateSelector)
const granted = useSelector(grantedSelector)
return (
<>
<SettingsIcon />
<Badge
badgeContent=""
color="error"
invisible={!needsUpdate || !granted}
style={{ paddingRight: '10px' }}
variant="dot"
>
Settings
</Badge>
</>
)
}
export default SettingsTab

View File

@ -1,21 +0,0 @@
import { secondary } from 'src/theme/variables'
import { createStyles } from '@material-ui/core'
export const styles = createStyles({
tabWrapper: {
display: 'flex',
flexDirection: 'row',
'& svg': {
display: 'block',
marginRight: '5px',
},
'& .fill': {
fill: 'rgba(0, 0, 0, 0.54)',
},
},
tabWrapperSelected: {
'& .fill': {
fill: secondary,
},
},
})

View File

@ -1,25 +0,0 @@
// TODO: remove this file. It's no longer used
import { screenSm, sm } from 'src/theme/variables'
import { createStyles } from '@material-ui/core'
export const styles = createStyles({
receiveModal: {
height: 'auto',
maxWidth: 'calc(100% - 30px)',
minHeight: '544px',
overflow: 'hidden',
},
receive: {
borderRadius: '4px',
marginLeft: sm,
width: '50%',
'& > span': {
fontSize: '14px',
},
[`@media (min-width: ${screenSm}px)`]: {
minWidth: '95px',
width: 'auto',
},
},
})

View File

@ -1,26 +0,0 @@
import * as React from 'react'
import Bold from 'src/components/layout/Bold'
import Button from 'src/components/layout/Button'
import Col from 'src/components/layout/Col'
import Link from 'src/components/layout/Link'
import Paragraph from 'src/components/layout/Paragraph/index'
import Row from 'src/components/layout/Row'
import { SAFELIST_ADDRESS } from 'src/routes/routes'
const NoRights = () => (
<Row>
<Col center="xs" margin="md" sm={10} smOffset={2} start="sm" xs={12}>
<Paragraph size="lg">
<Bold>Impossible load Safe, check its address and ownership</Bold>
</Paragraph>
</Col>
<Col center="xs" margin="md" sm={10} smOffset={2} start="sm" xs={12}>
<Button color="primary" component={Link} to={SAFELIST_ADDRESS} variant="contained">
Safe List
</Button>
</Col>
</Row>
)
export default NoRights

View File

@ -57,8 +57,8 @@ export const Advanced = (): React.ReactElement => {
Safe Nonce
</Title>
<InfoText size="lg">
For security reasons, transactions made with the Safe need to be executed in order. The nonce shows you which
transaction was executed most recently. You can find the nonce for a transaction in the transaction details.
For security reasons, transactions made with Gnosis Safe need to be executed in order. The nonce shows you
which transaction will be executed next. You can find the nonce for a transaction in the transaction details.
</InfoText>
<InfoText color="secondaryLight" size="xl">
Current Nonce: <Bold>{nonce}</Bold>

View File

@ -120,7 +120,7 @@ const SafeDetails = (): React.ReactElement => {
{() => (
<>
<Block className={classes.formContainer}>
<Heading tag="h2">Safe Version</Heading>
<Heading tag="h2">Contract Version</Heading>
<Row align="end" grow>
<StyledLink rel="noreferrer noopener" target="_blank" href={safeInfo?.deployerRepoUrl}>
<Text size="xl" as="span" color="primary">

View File

@ -38,7 +38,7 @@ export const NewLimitSteps = (): ReactElement => (
</Text>
<Text size="lg" color="placeHolder" center>
Choose an account that will benefit from this allowance.
Define beneficiary that will be able to use the allowance.
</Text>
<Text size="lg" color="placeHolder" center>

View File

@ -1,4 +1,5 @@
import { IconText } from '@gnosis.pm/safe-react-components'
import { IconText, Loader } from '@gnosis.pm/safe-react-components'
import { LoadingContainer } from 'src/components/LoaderContainer'
import Badge from '@material-ui/core/Badge'
import { makeStyles } from '@material-ui/core/styles'
import cn from 'classnames'
@ -15,7 +16,6 @@ import ThresholdSettings from './ThresholdSettings'
import RemoveSafeIcon from './assets/icons/bin.svg'
import { styles } from './style'
import Loader from 'src/components/Loader'
import Block from 'src/components/layout/Block'
import ButtonLink from 'src/components/layout/ButtonLink'
import Col from 'src/components/layout/Col'
@ -60,7 +60,9 @@ const Settings: React.FC = () => {
const { menuOptionIndex, showRemoveSafe } = state
return !owners ? (
<Loader />
<LoadingContainer>
<Loader size="md" />
</LoadingContainer>
) : (
<>
<Row className={classes.message}>

View File

@ -1,6 +1,5 @@
import { Dot, IconText as IconTextSrc, Text, Tooltip } from '@gnosis.pm/safe-react-components'
import { Dot, IconText as IconTextSrc, Loader, Text, Tooltip } from '@gnosis.pm/safe-react-components'
import { ThemeColors } from '@gnosis.pm/safe-react-components/dist/theme'
import CircularProgress from '@material-ui/core/CircularProgress'
import React, { ReactElement, useContext, useRef } from 'react'
import styled from 'styled-components'
@ -171,7 +170,7 @@ export const TxCollapsed = ({
<div className="tx-status" ref={sameString(lastItemId, transaction.id) ? ref : null}>
{transaction?.txStatus === 'PENDING' || transaction?.txStatus === 'PENDING_FAILED' ? (
<CircularProgressPainter color={status.color}>
<CircularProgress size={14} color="inherit" />
<Loader size="xs" color="pending" />
</CircularProgressPainter>
) : (
(transaction?.txStatus === 'AWAITING_EXECUTION' || transaction?.txStatus === 'AWAITING_CONFIRMATIONS') && (

View File

@ -16,7 +16,7 @@ export const TxInfoCreation = ({ transaction }: { transaction: Transaction }): R
<div className="tx-summary">
<div className="tx-hash">
<Text size="xl" strong as="span">
Hash:{' '}
Transaction hash:{' '}
</Text>
<InlineEthHashInfo
textSize="xl"

View File

@ -12,12 +12,13 @@ export const TxSummary = ({ txDetails }: { txDetails: ExpandedTxDetails }): Reac
const explorerUrl = txHash ? getExplorerInfo(txHash) : null
const nonce = isMultiSigExecutionDetails(detailedExecutionInfo) ? detailedExecutionInfo.nonce : undefined
const created = isMultiSigExecutionDetails(detailedExecutionInfo) ? detailedExecutionInfo.submittedAt : undefined
const safeTxHash = isMultiSigExecutionDetails(detailedExecutionInfo) ? detailedExecutionInfo.safeTxHash : undefined
return (
<>
<div className="tx-hash">
<Text size="xl" strong as="span">
Hash:{' '}
Transaction hash:{' '}
</Text>
{txHash ? (
<InlineEthHashInfo textSize="xl" hash={txHash} shortenHash={8} showCopyBtn explorerUrl={explorerUrl} />
@ -27,6 +28,14 @@ export const TxSummary = ({ txDetails }: { txDetails: ExpandedTxDetails }): Reac
</Text>
)}
</div>
{safeTxHash !== undefined && (
<div className="tx-hash">
<Text size="xl" strong as="span">
SafeTxHash:{' '}
</Text>
<InlineEthHashInfo textSize="xl" hash={safeTxHash} shortenHash={8} showCopyBtn />
</div>
)}
{nonce !== undefined && (
<div className="tx-nonce">
<Text size="xl" strong as="span">

View File

@ -516,7 +516,7 @@ export const Centered = styled.div<{ padding?: number }>`
export const HorizontallyCentered = styled(Centered)<{ isVisible: boolean }>`
visibility: ${({ isVisible }) => (isVisible ? 'visible' : 'hidden')};
height: auto;
height: 100px;
`
export const StyledAccordionSummary = styled(AccordionSummary)`

View File

@ -1,4 +1,4 @@
import { List, Map } from 'immutable'
import { List } from 'immutable'
import { createSelector } from 'reselect'
import { Token } from 'src/logic/tokens/store/model/token'
@ -7,7 +7,7 @@ import { getEthAsToken } from 'src/logic/tokens/utils/tokenHelpers'
import { isUserAnOwner, sameAddress } from 'src/logic/wallets/ethAddresses'
import { userAccountSelector } from 'src/logic/wallets/store/selectors'
import { safeActiveTokensSelector, safeBalancesSelector, safeSelector } from 'src/logic/safe/store/selectors'
import { safeBalancesSelector, safeSelector } from 'src/logic/safe/store/selectors'
import { SafeRecord } from 'src/logic/safe/store/models/safe'
export const grantedSelector = createSelector(
@ -25,28 +25,30 @@ const safeEthAsTokenSelector = createSelector(safeSelector, (safe?: SafeRecord):
})
export const extendedSafeTokensSelector = createSelector(
safeActiveTokensSelector,
safeBalancesSelector,
tokensSelector,
safeEthAsTokenSelector,
(safeTokens, balances, tokensList, ethAsToken): List<Token> => {
const extendedTokens = Map<string, Token>().withMutations((map) => {
safeTokens.forEach((tokenAddress) => {
const baseToken = tokensList.get(tokenAddress)
const tokenBalance = balances?.get(tokenAddress)
(safeBalances, tokensList, ethAsToken): List<Token> => {
const extendedTokens: Array<Token> = []
if (baseToken) {
const updatedBaseToken = baseToken.set('balance', tokenBalance || { tokenBalance: '0', fiatBalance: '0' })
if (sameAddress(tokenAddress, ethAsToken?.address)) {
map.set(tokenAddress, updatedBaseToken.set('logoUri', ethAsToken?.logoUri || baseToken.logoUri))
} else {
map.set(tokenAddress, updatedBaseToken)
}
}
})
safeBalances.forEach((safeBalance) => {
const tokenAddress = safeBalance.tokenAddress
if (!tokenAddress) {
return
}
const baseToken = sameAddress(tokenAddress, ethAsToken?.address) ? ethAsToken : tokensList.get(tokenAddress)
if (!baseToken) {
return
}
const token = baseToken.set('balance', safeBalance)
extendedTokens.push(token)
})
return extendedTokens.toList()
return List(extendedTokens)
},
)

View File

@ -77,7 +77,7 @@ export const WelcomeLayout = ({ isOldMultisigMigration }: Props): React.ReactEle
<Block>
{/* Title */}
<Title size="md" strong>
Welcome to Gnosis Safe Multisig.
Welcome to Gnosis Safe.
</Title>
{/* Subtitle */}
@ -89,8 +89,7 @@ export const WelcomeLayout = ({ isOldMultisigMigration }: Props): React.ReactEle
</>
) : (
<>
Gnosis Safe Multisig is the most trusted platform to manage digital assets. <br /> Here is how to get
started:{' '}
Gnosis Safe is the most trusted platform to manage digital assets. <br /> Here is how to get started:{' '}
</>
)}
</Title>
@ -108,8 +107,7 @@ export const WelcomeLayout = ({ isOldMultisigMigration }: Props): React.ReactEle
</StyledTitle>
</TitleWrapper>
<Text size="xl">
Gnosis Safe Multisig supports a wide range of wallets that you can choose to be one of the authentication
factors.
Gnosis Safe supports a wide range of wallets that you can choose to interact with your Safe.
</Text>
<StyledButtonLink textSize="xl" color="primary" iconType="externalLink" iconSize="sm">
<LinkSRC
@ -117,9 +115,9 @@ export const WelcomeLayout = ({ isOldMultisigMigration }: Props): React.ReactEle
href="https://help.gnosis-safe.io/en/articles/4689442-why-do-i-need-to-connect-a-wallet"
target="_blank"
rel="noopener noreferrer"
title="More info about: Why do I need to connect wallet?"
title="More info about: Why do I need to connect a wallet?"
>
Why do I need to connect wallet?
Why do I need to connect a wallet?
</LinkSRC>
</StyledButtonLink>
<StyledButton
@ -148,7 +146,7 @@ export const WelcomeLayout = ({ isOldMultisigMigration }: Props): React.ReactEle
</StyledTitle>
</TitleWrapper>
<Text size="xl">
Create a new Safe Multisig that is controlled by one or multiple owners. <br />
Create a new Safe that is controlled by one or multiple owners. <br />
You will be required to pay a network fee for creating your new Safe.
</Text>
<StyledButton size="lg" color="primary" variant="contained" component={Link} to={OPEN_ADDRESS}>
@ -163,11 +161,11 @@ export const WelcomeLayout = ({ isOldMultisigMigration }: Props): React.ReactEle
{/* Load safe */}
<CardsCol>
<StyledTitleOnly size="sm" strong withoutMargin>
Load existing Safe
Add existing Safe
</StyledTitleOnly>
<Text size="xl">
Already have a Safe? Do you want to access your Safe Multisig from a different device? Easily load your
Safe Multisig using your Safe address.
Already have a Safe? Do you want to access your Safe from a different device? Easily add it using your
Safe address.
</Text>
<StyledButton
variant="bordered"
@ -179,7 +177,7 @@ export const WelcomeLayout = ({ isOldMultisigMigration }: Props): React.ReactEle
to={LOAD_ADDRESS}
>
<Text size="xl" color="secondary">
Load existing Safe
Add existing Safe
</Text>
</StyledButton>
</CardsCol>

View File

@ -279,6 +279,11 @@ const theme = createMuiTheme({
'& > span': {
display: 'flex',
flexDirection: 'row',
alignItems: 'stretch',
overflowX: 'hidden',
overflowY: 'auto',
maxHeight: '160px',
wordBreak: 'break-word',
'& > img': {
display: 'block',
marginRight: '13px',

View File

@ -17,7 +17,7 @@ export const SQUARELINK_ID = {
*/
export const INFURA_TOKEN = process.env.REACT_APP_INFURA_TOKEN || ''
export const LATEST_SAFE_VERSION = process.env.REACT_APP_LATEST_SAFE_VERSION || '1.1.1'
export const LOADED_SAFE_KEY = 'LOADED SAFE'
export const LOADED_SAFE_KEY = 'Gnosis Safe'
export const APP_VERSION = process.env.REACT_APP_APP_VERSION || 'not-defined'
export const OPENSEA_API_KEY = process.env.REACT_APP_OPENSEA_API_KEY || ''
export const COLLECTIBLES_SOURCE = process.env.REACT_APP_COLLECTIBLES_SOURCE || 'Gnosis'
@ -25,6 +25,9 @@ export const TIMEOUT = process.env.NODE_ENV === 'test' ? 1500 : 5000
export const ETHERSCAN_API_KEY = process.env.REACT_APP_ETHERSCAN_API_KEY
export const EXCHANGE_RATE_URL = 'https://api.exchangeratesapi.io/latest'
export const EXCHANGE_RATE_URL_FALLBACK = 'https://api.coinbase.com/v2/exchange-rates'
export const SAFE_APPS_LIST_URL =
process.env.REACT_APP_SAFE_APPS_LIST_URL ||
'https://raw.githubusercontent.com/gnosis/safe-apps-list/main/public/gnosis-default.applist.json'
export const IPFS_GATEWAY = process.env.REACT_APP_IPFS_GATEWAY
export const SPENDING_LIMIT_MODULE_ADDRESS =
process.env.REACT_APP_SPENDING_LIMIT_MODULE_ADDRESS || '0xCFbFaC74C26F8647cBDb8c5caf80BB5b32E43134'

604
yarn.lock
View File

@ -1200,6 +1200,47 @@
resolved "https://registry.yarnpkg.com/@csstools/normalize.css/-/normalize.css-10.1.0.tgz#f0950bba18819512d42f7197e56c518aa491cf18"
integrity sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg==
"@cvbb/bc-bech32@^1.1.15":
version "1.1.15"
resolved "https://registry.yarnpkg.com/@cvbb/bc-bech32/-/bc-bech32-1.1.15.tgz#f337e1046ee8ee9256b11ab25efaf4c1311bd04a"
integrity sha512-e80x5VsfUCpXYiheLm/c/lOEegr7ZSd5nq3HlJEcfgljXW5LosH/Kgf21he9Yyr2cBke3NrZM7DuOxvbMpPJHg==
"@cvbb/bc-ur@^0.2.14":
version "0.2.15"
resolved "https://registry.yarnpkg.com/@cvbb/bc-ur/-/bc-ur-0.2.15.tgz#fc2f057b740c86c25b16d60f0ca7f97afd228ba7"
integrity sha512-jukQNKCzv1zxUsESeCbVV2Mkxmgz03yVmtgjPpqJ0D1HhNUz8pBt7tmLVOvAO1eeK4Q0083maebxv3r7p2uadA==
dependencies:
"@cvbb/bc-bech32" "^1.1.15"
"@types/sha.js" "^2.4.0"
sha.js "^2.4.11"
"@cvbb/eth-keyring@^1.1.0":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@cvbb/eth-keyring/-/eth-keyring-1.1.1.tgz#e681810e7f74d8682f6ee9b8f3844d5bbc9ef02f"
integrity sha512-HhSiHY3chN4nx1tajLD5v0obdr5GdIVGdLGCEOP8rG0f0Tu6bOJBqJE/idDii8C7mtxEijquyfyuPHHNfa8xKg==
dependencies:
"@cvbb/sdk" "^1.1.1"
ethereumjs-tx "^2.1.2"
ethereumjs-util "^7.0.8"
hdkey "^2.0.1"
"@cvbb/sdk@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@cvbb/sdk/-/sdk-1.1.1.tgz#a8343feff0a8e5781a60095c01895c86c1c58d5e"
integrity sha512-aEx914et/V/CXREVZiMrrS4VprCNFPsabTNZTzqNJOrMsOpABk0gwJHi55D+FaAsqIDK7PTLzkPjR59Iorol6Q==
dependencies:
"@cvbb/bc-ur" "^0.2.14"
"@types/qrcode.react" "^1.0.1"
"@types/react-dom" "^17.0.1"
"@types/react-modal" "^3.12.0"
"@types/react-qr-reader" "^2.1.3"
qrcode.react "^1.0.1"
react "^17.0.1"
react-dom "^17.0.1"
react-modal "^3.12.1"
react-qr-reader "^2.2.1"
rxjs "^6.6.3"
"@develar/schema-utils@~2.6.5":
version "2.6.5"
resolved "https://registry.yarnpkg.com/@develar/schema-utils/-/schema-utils-2.6.5.tgz#3ece22c5838402419a6e0425f85742b961d9b6c6"
@ -1596,9 +1637,9 @@
solc "0.5.14"
truffle "^5.1.21"
"@gnosis.pm/safe-react-components@https://github.com/gnosis/safe-react-components.git#2e427ee":
"@gnosis.pm/safe-react-components@https://github.com/gnosis/safe-react-components.git#b281238":
version "0.5.0"
resolved "https://github.com/gnosis/safe-react-components.git#2e427ee36694c7964301fc155b0c080101a34bed"
resolved "https://github.com/gnosis/safe-react-components.git#b2812381a265e9b0a17abbc11392986e6c1c74b8"
dependencies:
classnames "^2.2.6"
react-media "^1.10.0"
@ -1862,20 +1903,20 @@
dependencies:
invariant "2"
"@ledgerhq/devices@^5.45.0":
version "5.45.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-5.45.0.tgz#f39f42c2526a98bde2cb42af111848783f2394b1"
integrity sha512-wAtm4kvQ8pAdqdIpDa/OqU9rhtqI0sTdwDGGp4vthHiWNdBwqwPFcKmEki+mUgPCfRqn3SifyqaPqvFpvu+oWw==
"@ledgerhq/devices@^5.49.0":
version "5.49.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-5.49.0.tgz#86733944ea724acb974b136e46487a90ee0bfa6e"
integrity sha512-14VSO+NeR/O8VSXXnlBsA0DAluzanJVEjHLDJubU5NZjEttXVF9gdQh1j10+MKW0f8H23IkdqwswVQIB9ZPomQ==
dependencies:
"@ledgerhq/errors" "^5.43.0"
"@ledgerhq/logs" "^5.43.0"
rxjs "^6.6.6"
semver "^7.3.4"
"@ledgerhq/errors" "^5.49.0"
"@ledgerhq/logs" "^5.49.0"
rxjs "^6.6.7"
semver "^7.3.5"
"@ledgerhq/errors@^5.34.0", "@ledgerhq/errors@^5.43.0":
version "5.43.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-5.43.0.tgz#6bec77ebc31c4333a7f8d13b1f3f4d739b859b75"
integrity sha512-ZjKlUQbIn/DHXAefW3Y1VyDrlVhVqqGnXzrqbOXuDbZ2OAIfSe/A1mrlCbWt98jP/8EJQBuCzBOtnmpXIL/nYg==
"@ledgerhq/errors@^5.34.0", "@ledgerhq/errors@^5.43.0", "@ledgerhq/errors@^5.49.0":
version "5.49.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-5.49.0.tgz#8ecb43bb702504d9fc94ee12022d81d6e36cb5ce"
integrity sha512-+uhoSsAnzZiZ2CUk/dv4Uo8lrl0jn2izYJATSbC5aZFd0Yl7PWZ1SMHMkvPVEgQvWZcu4iQZ67rlKOtj5tUFWA==
"@ledgerhq/hw-app-eth@^5.21.0":
version "5.44.1"
@ -1888,27 +1929,27 @@
bignumber.js "^9.0.1"
rlp "^2.2.6"
"@ledgerhq/hw-transport-node-hid-noevents@^5.45.0":
version "5.45.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-node-hid-noevents/-/hw-transport-node-hid-noevents-5.45.0.tgz#a7c6d481d7ef73f03e3feddc6d07498c8de585a1"
integrity sha512-f0c1FKAo9r/bU8fbASAEP2uuU7hbbX7AfyrETu7Lx5yx6GmWzq/IL+FhnmWJyiwlwqH7HR71ivVYoEoM4veWCQ==
"@ledgerhq/hw-transport-node-hid-noevents@^5.49.0":
version "5.49.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-node-hid-noevents/-/hw-transport-node-hid-noevents-5.49.0.tgz#fe26890772b3167dc8c5a978d801e22d9baa62a5"
integrity sha512-Hly9Zl+EMG0V84FoemB7gig7h51w16216AqEUV4ztVofokpIWHi9upq9HolpSfTcodoO/Dp9bPri4tspN+tAOA==
dependencies:
"@ledgerhq/devices" "^5.45.0"
"@ledgerhq/errors" "^5.43.0"
"@ledgerhq/hw-transport" "^5.45.0"
"@ledgerhq/logs" "^5.43.0"
"@ledgerhq/devices" "^5.49.0"
"@ledgerhq/errors" "^5.49.0"
"@ledgerhq/hw-transport" "^5.49.0"
"@ledgerhq/logs" "^5.49.0"
node-hid "2.1.1"
"@ledgerhq/hw-transport-node-hid-singleton@5.45.0":
version "5.45.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-node-hid-singleton/-/hw-transport-node-hid-singleton-5.45.0.tgz#c29ac64927823493bc93996fc1aa7ed363e0bb1d"
integrity sha512-nJgT4eMTevC2vz/RXOmLn9U0B9Wp2BNSxeM/Z0Sh3lRtSS6dBLia1mZNhVpH+AfwvEnZ3Ta0lWZinUYY+ARH5g==
"@ledgerhq/hw-transport-node-hid-singleton@5.49.0":
version "5.49.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-node-hid-singleton/-/hw-transport-node-hid-singleton-5.49.0.tgz#f2a1f525229808d8542738d39b76330c6cb6b534"
integrity sha512-uQQvNxHqPP0ncTGsDm8vi7CYeq5wchaN+TSDWa+hz7qKKwih5Wke+9i+hOkLbTyU/P79QOerrjoiC11tuVh9vA==
dependencies:
"@ledgerhq/devices" "^5.45.0"
"@ledgerhq/errors" "^5.43.0"
"@ledgerhq/hw-transport" "^5.45.0"
"@ledgerhq/hw-transport-node-hid-noevents" "^5.45.0"
"@ledgerhq/logs" "^5.43.0"
"@ledgerhq/devices" "^5.49.0"
"@ledgerhq/errors" "^5.49.0"
"@ledgerhq/hw-transport" "^5.49.0"
"@ledgerhq/hw-transport-node-hid-noevents" "^5.49.0"
"@ledgerhq/logs" "^5.49.0"
lodash "^4.17.21"
node-hid "2.1.1"
usb-detection "^4.10.0"
@ -1923,19 +1964,19 @@
"@ledgerhq/logs" "^5.30.0"
u2f-api "0.2.7"
"@ledgerhq/hw-transport@^5.34.0", "@ledgerhq/hw-transport@^5.43.0", "@ledgerhq/hw-transport@^5.45.0":
version "5.45.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-5.45.0.tgz#5d1e23d61d99664faf29609dbd4a5ca6d1f4c1bc"
integrity sha512-YDkPQ2u5BJaMk2rJ8jcSucCv1JRUhmlaWUOvZ+Q7I8VNnvBM+N5yc9nqRX8TuHRlbPyiFm8xjEkPktVejuTAvQ==
"@ledgerhq/hw-transport@^5.34.0", "@ledgerhq/hw-transport@^5.43.0", "@ledgerhq/hw-transport@^5.49.0":
version "5.49.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-5.49.0.tgz#f0c7c22c19e38d9338ec1056713f80e0a669cc31"
integrity sha512-mfQNSxZ3cTXo+l6SEM+D92YaW46GkP1IiWo9OkHPnsq8y8IxSD6QJOEiAAZtvpGvV1eRqqrVyanoFRTuHcZjZA==
dependencies:
"@ledgerhq/devices" "^5.45.0"
"@ledgerhq/errors" "^5.43.0"
"@ledgerhq/devices" "^5.49.0"
"@ledgerhq/errors" "^5.49.0"
events "^3.3.0"
"@ledgerhq/logs@^5.30.0", "@ledgerhq/logs@^5.43.0":
version "5.43.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/logs/-/logs-5.43.0.tgz#031bad4b8a3525c5e14210afde0bc09c79564026"
integrity sha512-QWfQjea3ekh9ZU+JeL2tJC9cTKLZ/JrcS0JGatLejpRYxQajvnHvHfh0dbHOKXEaXfCskEPTZ3f1kzuts742GA==
"@ledgerhq/logs@^5.30.0", "@ledgerhq/logs@^5.49.0":
version "5.49.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/logs/-/logs-5.49.0.tgz#e14e34df1605c17d6b90eb32c591c7b3de3fbae8"
integrity sha512-Ynl2JzRwh8l9PoXrDNihXEicpVo6Ra2lYZoqSYfVH/v/2/TSa/JB9Qll8P85XFYkS3ouDTTbp1S5KViaTkqD5g==
"@malept/cross-spawn-promise@^1.1.0":
version "1.1.1"
@ -2236,90 +2277,91 @@
estree-walker "^1.0.1"
picomatch "^2.2.2"
"@sentry/browser@6.2.1":
version "6.2.1"
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.2.1.tgz#f9f277e6f8cad0c7efd1a01726095d63a47a1c16"
integrity sha512-OAikFZ9EimD3noxMp8tA6Cf6qJcQ2U8k5QSgTPwdx+09nZOGJzbRFteK7WWmrS93ZJdzN61lpSQbg5v+bmmfbQ==
"@sentry/browser@6.2.5":
version "6.2.5"
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.2.5.tgz#35e259e16521d26f348a06b31eb495e0033111d6"
integrity sha512-nlvaE+D7oaj4MxoY9ikw+krQDOjftnDYJQnOwOraXPk7KYM6YwmkakLuE+x/AkaH3FQVTQF330VAa9d6SWETlA==
dependencies:
"@sentry/core" "6.2.1"
"@sentry/types" "6.2.1"
"@sentry/utils" "6.2.1"
"@sentry/core" "6.2.5"
"@sentry/types" "6.2.5"
"@sentry/utils" "6.2.5"
tslib "^1.9.3"
"@sentry/cli@^1.63.1":
version "1.63.1"
resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-1.63.1.tgz#306a0591190432574082d4ce4a72363201972461"
integrity sha512-qksIcrnObkGvtubs1FmW4EMXLo7R43Dobgzuxnyoebo1Y5KfRLziiw6H+ux8D4c1Nui4SuvDGDq0ObAfO5oE6Q==
"@sentry/cli@^1.64.0":
version "1.64.0"
resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-1.64.0.tgz#8eadb93118ad295b0ac49de55a80eeb5a682c403"
integrity sha512-MHWHiYVBJaE0y/JVSziZIclBYhINiI4VsJ10r7rcJYAwDah3JYBPMrv0iwmuxBVWRFMSuAmSpivkzn67JS6sPg==
dependencies:
https-proxy-agent "^5.0.0"
mkdirp "^0.5.5"
node-fetch "^2.6.0"
npmlog "^4.1.2"
progress "^2.0.3"
proxy-from-env "^1.1.0"
"@sentry/core@6.2.1":
version "6.2.1"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.2.1.tgz#8b177e9bf591e2e7ddcb04f0b1403de3f5aa8755"
integrity sha512-jPqQEtafxxDtLONhCbTHh/Uq8mZRhsfbwJTSVYfPVEe/ELfFZLQK7tP6rOh7zEWKbTkE0mE6XcaoH3ZRAhgrqg==
"@sentry/core@6.2.5":
version "6.2.5"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.2.5.tgz#e75093f8598becc0a4a0be927f32f7ac49e8588f"
integrity sha512-I+AkgIFO6sDUoHQticP6I27TT3L+i6TUS03in3IEtpBcSeP2jyhlxI8l/wdA7gsBqUPdQ4GHOOaNgtFIcr8qag==
dependencies:
"@sentry/hub" "6.2.1"
"@sentry/minimal" "6.2.1"
"@sentry/types" "6.2.1"
"@sentry/utils" "6.2.1"
"@sentry/hub" "6.2.5"
"@sentry/minimal" "6.2.5"
"@sentry/types" "6.2.5"
"@sentry/utils" "6.2.5"
tslib "^1.9.3"
"@sentry/hub@6.2.1":
version "6.2.1"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.2.1.tgz#35bc6bf841a93f4354b3a17592c938b3dba20b73"
integrity sha512-pG7wCQeRpzeP6t0bT4T0X029R19dbDS3/qswF8BL6bg0AI3afjfjBAZm/fqn1Uwe/uBoMHVVdbxgJDZeQ5d4rQ==
"@sentry/hub@6.2.5":
version "6.2.5"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.2.5.tgz#324cae0c90d736cd1032e94104bf3f18becec4d6"
integrity sha512-YlEFdEhcfqpl2HC+/dWXBsBJEljyMzFS7LRRjCk8QANcOdp9PhwQjwebUB4/ulOBjHPP2WZk7fBBd/IKDasTUg==
dependencies:
"@sentry/types" "6.2.1"
"@sentry/utils" "6.2.1"
"@sentry/types" "6.2.5"
"@sentry/utils" "6.2.5"
tslib "^1.9.3"
"@sentry/minimal@6.2.1":
version "6.2.1"
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.2.1.tgz#8f01480e1b56bc7dd54adf925e5317f233e19384"
integrity sha512-wuSXB4Ayxv9rBEQ4pm7fnG4UU2ZPtPnnChoEfd4/mw1UthXSvmPFEn6O4pdo2G8fTkl8eqm6wT/Q7uIXMEmw+A==
"@sentry/minimal@6.2.5":
version "6.2.5"
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.2.5.tgz#3e963e868bfa68e97581403521fd4e09a8965b02"
integrity sha512-RKP4Qx3p7Cv0oX1cPKAkNVFYM7p2k1t32cNk1+rrVQS4hwlJ7Eg6m6fsqsO+85jd6Ne/FnyYsfo9cDD3ImTlWQ==
dependencies:
"@sentry/hub" "6.2.1"
"@sentry/types" "6.2.1"
"@sentry/hub" "6.2.5"
"@sentry/types" "6.2.5"
tslib "^1.9.3"
"@sentry/react@^6.2.1":
version "6.2.1"
resolved "https://registry.yarnpkg.com/@sentry/react/-/react-6.2.1.tgz#26587f3f47e9699003b04ac558d8aa8a2b7416d7"
integrity sha512-emJnYVASM2hej2f8eSjqiDRMljwLsDJDSwa6kVc5HUOs9gnVrE4MR+vSywraACf5tKZbH1YI+NUXCmR++fIB0g==
version "6.2.5"
resolved "https://registry.yarnpkg.com/@sentry/react/-/react-6.2.5.tgz#c9bc01332ac5f75eb76937ae7d91b6bb43d5b996"
integrity sha512-uYsLHUYMya2H9WtF5Eoy9WQ2SnuMDsW2q9kDpdW1A59kCKp4O1t6qEVvDyxkz8r+Mk+OhjmFdbX4F/H8KZMVBQ==
dependencies:
"@sentry/browser" "6.2.1"
"@sentry/minimal" "6.2.1"
"@sentry/types" "6.2.1"
"@sentry/utils" "6.2.1"
"@sentry/browser" "6.2.5"
"@sentry/minimal" "6.2.5"
"@sentry/types" "6.2.5"
"@sentry/utils" "6.2.5"
hoist-non-react-statics "^3.3.2"
tslib "^1.9.3"
"@sentry/tracing@^6.2.1":
version "6.2.1"
resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.2.1.tgz#61c18c43c5390c348b35dafe73947ab379252d8f"
integrity sha512-bvStY1SnL08wkSeVK3j9K5rivQQJdKFCPR2VYRFOCaUoleZ6ChPUnBvxQ/E2LXc0hk/y/wo1q4r5B0dfCCY+bQ==
version "6.2.5"
resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.2.5.tgz#3f5dadfdccdb5c1fb2eef68458c7c34329b0a34a"
integrity sha512-j/hM0BoHxfrNLxPeEJ5Vq4R34hO/TOHMEpLR3FdnunBXbsmjoKMMygIkPxnpML5XWtvukAehbwpDXldwMYz83w==
dependencies:
"@sentry/hub" "6.2.1"
"@sentry/minimal" "6.2.1"
"@sentry/types" "6.2.1"
"@sentry/utils" "6.2.1"
"@sentry/hub" "6.2.5"
"@sentry/minimal" "6.2.5"
"@sentry/types" "6.2.5"
"@sentry/utils" "6.2.5"
tslib "^1.9.3"
"@sentry/types@6.2.1":
version "6.2.1"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.2.1.tgz#28c946230b2023f72307b65606d32052ad9e5353"
integrity sha512-h0OV1QT+fv5ojfK5/+iEXClu33HirmvbjcQC2jf05IHj9yXIOWy6EB10S8nBjuLiiFqQiAQYj3FN9Ip4eN8NJA==
"@sentry/types@6.2.5":
version "6.2.5"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.2.5.tgz#34b75285b149e0b9bc5fd54fcc2c445d978c7f2e"
integrity sha512-1Sux6CLYrV9bETMsGP/HuLFLouwKoX93CWzG8BjMueW+Di0OGxZphYjXrGuDs8xO8bAKEVGCHgVQdcB2jevS0w==
"@sentry/utils@6.2.1":
version "6.2.1"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.2.1.tgz#bfcb12c20d44bf2aeb0073b1264703c11c179ebd"
integrity sha512-6kQgM/yBPdXu+3qbJnI6HBcWztN9QfiMkH++ZiKk4ERhg9d2LYWlze478uTU5Fyo/JQYcp+McpjtjpR9QIrr0g==
"@sentry/utils@6.2.5":
version "6.2.5"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.2.5.tgz#be90d056b09ed1216097d7a29e3e81ba39238e1b"
integrity sha512-fJoLUZHrd5MPylV1dT4qL74yNFDl1Ur/dab+pKNSyvnHPnbZ/LRM7aJ8VaRY/A7ZdpRowU+E14e/Yeem2c6gtQ==
dependencies:
"@sentry/types" "6.2.1"
"@sentry/types" "6.2.5"
tslib "^1.9.3"
"@sideway/address@^4.1.0":
@ -2960,10 +3002,10 @@
lz-string "^1.4.4"
pretty-format "^26.6.2"
"@testing-library/jest-dom@^5.11.6":
version "5.11.9"
resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.11.9.tgz#e6b3cd687021f89f261bd53cbe367041fbd3e975"
integrity sha512-Mn2gnA9d1wStlAIT2NU8J15LNob0YFBVjs2aEQ3j8rsfRQo+lAs7/ui1i2TGaJjapLmuNPLTsrm+nPjmZDwpcQ==
"@testing-library/jest-dom@^5.11.10":
version "5.11.10"
resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.11.10.tgz#1cd90715023e1627f5ed26ab3b38e6f22d77046c"
integrity sha512-FuKiq5xuk44Fqm0000Z9w0hjOdwZRNzgx7xGGxQYepWFZy+OYUMOT/wPI4nLYXCaVltNVpU1W/qmD88wLWDsqQ==
dependencies:
"@babel/runtime" "^7.9.2"
"@types/testing-library__jest-dom" "^5.9.1"
@ -2974,10 +3016,10 @@
lodash "^4.17.15"
redent "^3.0.0"
"@testing-library/react@^11.2.2":
version "11.2.5"
resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-11.2.5.tgz#ae1c36a66c7790ddb6662c416c27863d87818eb9"
integrity sha512-yEx7oIa/UWLe2F2dqK0FtMF9sJWNXD+2PPtp39BvE0Kh9MJ9Kl0HrZAgEuhUJR+Lx8Di6Xz+rKwSdEPY2UV8ZQ==
"@testing-library/react@^11.2.6":
version "11.2.6"
resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-11.2.6.tgz#586a23adc63615985d85be0c903f374dab19200b"
integrity sha512-TXMCg0jT8xmuU8BkKMtp8l7Z50Ykew5WNX8UoIKTaLFwKkP2+1YDhOLA2Ga3wY4x29jyntk7EWfum0kjlYiSjQ==
dependencies:
"@babel/runtime" "^7.12.5"
"@testing-library/dom" "^7.28.1"
@ -3352,6 +3394,13 @@
dependencies:
"@types/node" "*"
"@types/bn.js@^5.1.0":
version "5.1.0"
resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.0.tgz#32c5d271503a12653c62cf4d2b45e6eab8cebc68"
integrity sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA==
dependencies:
"@types/node" "*"
"@types/debug@^4.1.5":
version "4.1.5"
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.5.tgz#b14efa8852b7768d898906613c23f688713e02cd"
@ -3444,10 +3493,10 @@
dependencies:
"@types/istanbul-lib-report" "*"
"@types/jest@*", "@types/jest@^26.0.16":
version "26.0.20"
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.20.tgz#cd2f2702ecf69e86b586e1f5223a60e454056307"
integrity sha512-9zi2Y+5USJRxd0FsahERhBwlcvFh6D2GLQnY2FH2BzK8J9s9omvNHIbvABwIluXa0fD8XVKMLTO0aOEuUfACAA==
"@types/jest@*", "@types/jest@^26.0.22":
version "26.0.22"
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.22.tgz#8308a1debdf1b807aa47be2838acdcd91e88fbe6"
integrity sha512-eeWwWjlqxvBxc4oQdkueW5OF/gtfSceKk4OnOAGlUSwS/liBRtZppbJuz1YkgbrbfGOoeBHun9fOvXnjNwrSOw==
dependencies:
jest-diff "^26.0.0"
pretty-format "^26.0.0"
@ -3493,26 +3542,21 @@
dependencies:
"@types/node" "*"
"@types/node@*", "@types/node@^14.14.30":
version "14.14.32"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.32.tgz#90c5c4a8d72bbbfe53033f122341343249183448"
integrity sha512-/Ctrftx/zp4m8JOujM5ZhwzlWLx22nbQJiVqz8/zE15gOeEW+uly3FSX4fGFpcfEvFzXcMCJwq9lGVWgyARXhg==
"@types/node@*", "@types/node@^14.14.37":
version "14.14.37"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.37.tgz#a3dd8da4eb84a996c36e331df98d82abd76b516e"
integrity sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw==
"@types/node@^10.12.18":
version "10.17.54"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.54.tgz#a737488631aca3ec7bd9f6229d77f1079e444793"
integrity sha512-c8Lm7+hXdSPmWH4B9z/P/xIXhFK3mCQin4yCYMd2p1qpMG5AfgyJuYZ+3q2dT7qLiMMMGMd5dnkFpdqJARlvtQ==
"@types/node@^12.0.12":
"@types/node@^12.0.12", "@types/node@^12.12.6", "@types/node@^12.6.1":
version "12.20.5"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.5.tgz#4ca82a766f05c359fd6c77505007e5a272f4bb9b"
integrity sha512-5Oy7tYZnu3a4pnJ//d4yVvOImExl4Vtwf0D40iKUlU+XlUsyV9iyFWyCFlwy489b72FMAik/EFwRkNLjjOdSPg==
"@types/node@^12.12.6", "@types/node@^12.6.1":
version "12.20.4"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.4.tgz#73687043dd00fcb6962c60fbf499553a24d6bdf2"
integrity sha512-xRCgeE0Q4pT5UZ189TJ3SpYuX/QGl6QIAOAIeDSbAVAd2gX1NxSZup4jNVK7cxIeP8KDSbJgcckun495isP1jQ==
"@types/normalize-package-data@^2.4.0":
version "2.4.0"
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
@ -3558,6 +3602,13 @@
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24"
integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==
"@types/qrcode.react@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@types/qrcode.react/-/qrcode.react-1.0.1.tgz#0904e7a075a6274a5258f19567b4f64013c159d8"
integrity sha512-PcVCjpsiT2KFKfJibOgTQtkt0QQT/6GbQUp1Np/hMPhwUzMJ2DRUkR9j7tXN9Q8X06qukw+RbaJ8lJ22SBod+Q==
dependencies:
"@types/react" "*"
"@types/reach__router@^1.2.3":
version "1.3.7"
resolved "https://registry.yarnpkg.com/@types/reach__router/-/reach__router-1.3.7.tgz#de8ab374259ae7f7499fc1373b9697a5f3cd6428"
@ -3565,14 +3616,35 @@
dependencies:
"@types/react" "*"
"@types/react-dom@^16.9.9":
version "16.9.11"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.11.tgz#752e223a1592a2c10f2668b215a0e0667f4faab1"
integrity sha512-3UuR4MoWf5spNgrG6cwsmT9DdRghcR4IDFOzNZ6+wcmacxkFykcb5ji0nNVm9ckBT4BCxvCrJJbM4+EYsEEVIg==
"@types/react-dom@^16.9.12":
version "16.9.12"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.12.tgz#55cd6b17e73922edb9545e5355a0016c1734e6f4"
integrity sha512-i7NPZZpPte3jtVOoW+eLB7G/jsX5OM6GqQnH+lC0nq0rqwlK0x8WcMEvYDgFWqWhWMlTltTimzdMax6wYfZssA==
dependencies:
"@types/react" "^16"
"@types/react-redux@^7.1.11":
"@types/react-dom@^17.0.1":
version "17.0.3"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.3.tgz#7fdf37b8af9d6d40127137865bb3fff8871d7ee1"
integrity sha512-4NnJbCeWE+8YBzupn/YrJxZ8VnjcJq5iR1laqQ1vkpQgBiA7bwk0Rp24fxsdNinzJY2U+HHS4dJJDPdoMjdJ7w==
dependencies:
"@types/react" "*"
"@types/react-modal@^3.12.0":
version "3.12.0"
resolved "https://registry.yarnpkg.com/@types/react-modal/-/react-modal-3.12.0.tgz#91fa86a76fd7fc57e36d2cf9b76efe5735a855a1"
integrity sha512-UnHu/YO73NZLwqFpju/c0tqiswR0UHIfeO16rkfLVJUIMfQsl7X0CBm99H5XXgBMe/PgtQ/Rkud72iuRBr1TeA==
dependencies:
"@types/react" "*"
"@types/react-qr-reader@^2.1.3":
version "2.1.3"
resolved "https://registry.yarnpkg.com/@types/react-qr-reader/-/react-qr-reader-2.1.3.tgz#cf3a27e7bde37a585a7baff8dbf242d1ebe70ddd"
integrity sha512-quTZl76whDvR+Xp87jh2roDbL6SC8Pzi8Ef59EP5RheobKZWQBbcDM33r7/Ndi63NBOz89MEDtkiHDkAvXxPhg==
dependencies:
"@types/react" "*"
"@types/react-redux@^7.1.11", "@types/react-redux@^7.1.16":
version "7.1.16"
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.16.tgz#0fbd04c2500c12105494c83d4a3e45c084e3cb21"
integrity sha512-f/FKzIrZwZk7YEO9E1yoxIuDNRiDducxkFlkw/GNMGEnK9n4K8wJzlJBghpSuOVDgEUHoDkDF7Gi9lHNQR4siw==
@ -3666,6 +3738,13 @@
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.4.tgz#43d7168fec6fa0988bb1a513a697b29296721afb"
integrity sha512-+nVsLKlcUCeMzD2ufHEYuJ9a2ovstb6Dp52A5VsoKxDXgvE051XgHI/33I1EymwkRGQkwnA0LkhnUzituGs4EQ==
"@types/sha.js@^2.4.0":
version "2.4.0"
resolved "https://registry.yarnpkg.com/@types/sha.js/-/sha.js-2.4.0.tgz#bce682ef860b40f419d024fa08600c3b8d24bb01"
integrity sha512-amxKgPy6WJTKuw8mpUwjX2BSxuBtBmZfRwIUDIuPJKNwGN8CWDli8JTg5ONTWOtcTkHIstvT7oAhhYXqEjStHQ==
dependencies:
"@types/node" "*"
"@types/source-list-map@*":
version "0.1.2"
resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9"
@ -3676,10 +3755,10 @@
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz#7036640b4e21cc2f259ae826ce843d277dad8cff"
integrity sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==
"@types/styled-components@^5.1.4":
version "5.1.7"
resolved "https://registry.yarnpkg.com/@types/styled-components/-/styled-components-5.1.7.tgz#3cd10b088c1cb1acde2e4b166b3e8275a3083710"
integrity sha512-BJzPhFygYspyefAGFZTZ/8lCEY4Tk+Iqktvnko3xmJf9LrLqs3+grxPeU3O0zLl6yjbYBopD0/VikbHgXDbJtA==
"@types/styled-components@^5.1.9":
version "5.1.9"
resolved "https://registry.yarnpkg.com/@types/styled-components/-/styled-components-5.1.9.tgz#00d3d84b501420521c4db727e3c195459f87a6cf"
integrity sha512-kbEG6YlwK8rucITpKEr6pA4Ho9KSQHUUOzZ9lY3va1mtcjvS3D0wDciFyHEiNHKLL/npZCKDQJqm0x44sPO9oA==
dependencies:
"@types/hoist-non-react-statics" "*"
"@types/react" "*"
@ -3747,13 +3826,13 @@
dependencies:
"@types/yargs-parser" "*"
"@typescript-eslint/eslint-plugin@^4.17.0", "@typescript-eslint/eslint-plugin@^4.5.0":
version "4.17.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.17.0.tgz#6f856eca4e6a52ce9cf127dfd349096ad936aa2d"
integrity sha512-/fKFDcoHg8oNan39IKFOb5WmV7oWhQe1K6CDaAVfJaNWEhmfqlA24g+u1lqU5bMH7zuNasfMId4LaYWC5ijRLw==
"@typescript-eslint/eslint-plugin@^4.22.0", "@typescript-eslint/eslint-plugin@^4.5.0":
version "4.22.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.22.0.tgz#3d5f29bb59e61a9dba1513d491b059e536e16dbc"
integrity sha512-U8SP9VOs275iDXaL08Ln1Fa/wLXfj5aTr/1c0t0j6CdbOnxh+TruXu1p4I0NAvdPBQgoPjHsgKn28mOi0FzfoA==
dependencies:
"@typescript-eslint/experimental-utils" "4.17.0"
"@typescript-eslint/scope-manager" "4.17.0"
"@typescript-eslint/experimental-utils" "4.22.0"
"@typescript-eslint/scope-manager" "4.22.0"
debug "^4.1.1"
functional-red-black-tree "^1.0.1"
lodash "^4.17.15"
@ -3761,15 +3840,15 @@
semver "^7.3.2"
tsutils "^3.17.1"
"@typescript-eslint/experimental-utils@4.17.0", "@typescript-eslint/experimental-utils@^4.0.1":
version "4.17.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.17.0.tgz#762c44aaa1a6a3c05b6d63a8648fb89b89f84c80"
integrity sha512-ZR2NIUbnIBj+LGqCFGQ9yk2EBQrpVVFOh9/Kd0Lm6gLpSAcCuLLe5lUCibKGCqyH9HPwYC0GIJce2O1i8VYmWA==
"@typescript-eslint/experimental-utils@4.22.0", "@typescript-eslint/experimental-utils@^4.0.1":
version "4.22.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.22.0.tgz#68765167cca531178e7b650a53456e6e0bef3b1f"
integrity sha512-xJXHHl6TuAxB5AWiVrGhvbGL8/hbiCQ8FiWwObO3r0fnvBdrbWEDy1hlvGQOAWc6qsCWuWMKdVWlLAEMpxnddg==
dependencies:
"@types/json-schema" "^7.0.3"
"@typescript-eslint/scope-manager" "4.17.0"
"@typescript-eslint/types" "4.17.0"
"@typescript-eslint/typescript-estree" "4.17.0"
"@typescript-eslint/scope-manager" "4.22.0"
"@typescript-eslint/types" "4.22.0"
"@typescript-eslint/typescript-estree" "4.22.0"
eslint-scope "^5.0.0"
eslint-utils "^2.0.0"
@ -3784,33 +3863,33 @@
eslint-scope "^5.0.0"
eslint-utils "^2.0.0"
"@typescript-eslint/parser@^4.17.0", "@typescript-eslint/parser@^4.5.0":
version "4.17.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.17.0.tgz#141b647ffc72ebebcbf9b0fe6087f65b706d3215"
integrity sha512-KYdksiZQ0N1t+6qpnl6JeK9ycCFprS9xBAiIrw4gSphqONt8wydBw4BXJi3C11ywZmyHulvMaLjWsxDjUSDwAw==
"@typescript-eslint/parser@^4.22.0", "@typescript-eslint/parser@^4.5.0":
version "4.22.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.22.0.tgz#e1637327fcf796c641fe55f73530e90b16ac8fe8"
integrity sha512-z/bGdBJJZJN76nvAY9DkJANYgK3nlRstRRi74WHm3jjgf2I8AglrSY+6l7ogxOmn55YJ6oKZCLLy+6PW70z15Q==
dependencies:
"@typescript-eslint/scope-manager" "4.17.0"
"@typescript-eslint/types" "4.17.0"
"@typescript-eslint/typescript-estree" "4.17.0"
"@typescript-eslint/scope-manager" "4.22.0"
"@typescript-eslint/types" "4.22.0"
"@typescript-eslint/typescript-estree" "4.22.0"
debug "^4.1.1"
"@typescript-eslint/scope-manager@4.17.0":
version "4.17.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.17.0.tgz#f4edf94eff3b52a863180f7f89581bf963e3d37d"
integrity sha512-OJ+CeTliuW+UZ9qgULrnGpPQ1bhrZNFpfT/Bc0pzNeyZwMik7/ykJ0JHnQ7krHanFN9wcnPK89pwn84cRUmYjw==
"@typescript-eslint/scope-manager@4.22.0":
version "4.22.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.22.0.tgz#ed411545e61161a8d702e703a4b7d96ec065b09a"
integrity sha512-OcCO7LTdk6ukawUM40wo61WdeoA7NM/zaoq1/2cs13M7GyiF+T4rxuA4xM+6LeHWjWbss7hkGXjFDRcKD4O04Q==
dependencies:
"@typescript-eslint/types" "4.17.0"
"@typescript-eslint/visitor-keys" "4.17.0"
"@typescript-eslint/types" "4.22.0"
"@typescript-eslint/visitor-keys" "4.22.0"
"@typescript-eslint/types@3.10.1":
version "3.10.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-3.10.1.tgz#1d7463fa7c32d8a23ab508a803ca2fe26e758727"
integrity sha512-+3+FCUJIahE9q0lDi1WleYzjCwJs5hIsbugIgnbB+dSCYUxl8L6PwmsyOPFZde2hc1DlTo/xnkOgiTLSyAbHiQ==
"@typescript-eslint/types@4.17.0":
version "4.17.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.17.0.tgz#f57d8fc7f31b348db946498a43050083d25f40ad"
integrity sha512-RN5z8qYpJ+kXwnLlyzZkiJwfW2AY458Bf8WqllkondQIcN2ZxQowAToGSd9BlAUZDB5Ea8I6mqL2quGYCLT+2g==
"@typescript-eslint/types@4.22.0":
version "4.22.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.22.0.tgz#0ca6fde5b68daf6dba133f30959cc0688c8dd0b6"
integrity sha512-sW/BiXmmyMqDPO2kpOhSy2Py5w6KvRRsKZnV0c4+0nr4GIcedJwXAq+RHNK4lLVEZAJYFltnnk1tJSlbeS9lYA==
"@typescript-eslint/typescript-estree@3.10.1":
version "3.10.1"
@ -3826,13 +3905,13 @@
semver "^7.3.2"
tsutils "^3.17.1"
"@typescript-eslint/typescript-estree@4.17.0":
version "4.17.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.17.0.tgz#b835d152804f0972b80dbda92477f9070a72ded1"
integrity sha512-lRhSFIZKUEPPWpWfwuZBH9trYIEJSI0vYsrxbvVvNyIUDoKWaklOAelsSkeh3E2VBSZiNe9BZ4E5tYBZbUczVQ==
"@typescript-eslint/typescript-estree@4.22.0":
version "4.22.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.22.0.tgz#b5d95d6d366ff3b72f5168c75775a3e46250d05c"
integrity sha512-TkIFeu5JEeSs5ze/4NID+PIcVjgoU3cUQUIZnH3Sb1cEn1lBo7StSV5bwPuJQuoxKXlzAObjYTilOEKRuhR5yg==
dependencies:
"@typescript-eslint/types" "4.17.0"
"@typescript-eslint/visitor-keys" "4.17.0"
"@typescript-eslint/types" "4.22.0"
"@typescript-eslint/visitor-keys" "4.22.0"
debug "^4.1.1"
globby "^11.0.1"
is-glob "^4.0.1"
@ -3846,12 +3925,12 @@
dependencies:
eslint-visitor-keys "^1.1.0"
"@typescript-eslint/visitor-keys@4.17.0":
version "4.17.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.17.0.tgz#9c304cfd20287c14a31d573195a709111849b14d"
integrity sha512-WfuMN8mm5SSqXuAr9NM+fItJ0SVVphobWYkWOwQ1odsfC014Vdxk/92t4JwS1Q6fCA/ABfCKpa3AVtpUKTNKGQ==
"@typescript-eslint/visitor-keys@4.22.0":
version "4.22.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.22.0.tgz#169dae26d3c122935da7528c839f42a8a42f6e47"
integrity sha512-nnMu4F+s4o0sll6cBSsTeVsT4cwxB7zECK3dFxzEjPBii9xLpq4yqqsy/FU5zMfan6G60DKZSCXAa3sHJZrcYw==
dependencies:
"@typescript-eslint/types" "4.17.0"
"@typescript-eslint/types" "4.22.0"
eslint-visitor-keys "^2.0.0"
"@unstoppabledomains/resolution@^1.17.0":
@ -5974,11 +6053,12 @@ bn.js@^5.0.0, bn.js@^5.1.1, bn.js@^5.1.2, bn.js@^5.1.3:
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002"
integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==
bnc-onboard@~1.20.0:
version "1.20.0"
resolved "https://registry.yarnpkg.com/bnc-onboard/-/bnc-onboard-1.20.0.tgz#436aa89a2839d6d0702a7689a9ca60f4a957d3cf"
integrity sha512-bt1pfEBFLnkuxzTQsvous/a28WufVJNVyi3MQwaSlC8IkIsZdih2dwiuhUd1HzGNzUFVk1xe9huxwb/7wEDl0w==
bnc-onboard@~1.22.0:
version "1.22.0"
resolved "https://registry.yarnpkg.com/bnc-onboard/-/bnc-onboard-1.22.0.tgz#3f81ea9405b9a5f1919785017beb148075500698"
integrity sha512-Vh9c+tDcs+Ca94KxutZk9xaQUFnlyHTg3zItAd2ivZwYFhoKAkvkV7CuEc3E7IIlP9y2ay+ghoBCbaicyVFHlQ==
dependencies:
"@cvbb/eth-keyring" "^1.1.0"
"@ledgerhq/hw-app-eth" "^5.21.0"
"@ledgerhq/hw-transport-u2f" "^5.21.0"
"@portis/web3" "^2.0.0-beta.57"
@ -7236,20 +7316,20 @@ concat-stream@^1.5.0, concat-stream@^1.5.1, concat-stream@^1.6.2:
readable-stream "^2.2.2"
typedarray "^0.0.6"
concurrently@^5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-5.3.0.tgz#7500de6410d043c912b2da27de3202cb489b1e7b"
integrity sha512-8MhqOB6PWlBfA2vJ8a0bSFKATOdWlHiQlk11IfmQBPaHVP8oP2gsh2MObE6UR3hqDHqvaIvLTyceNW6obVuFHQ==
concurrently@^6.0.0:
version "6.0.2"
resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-6.0.2.tgz#4ecdfc78a72a6f626a3a5d3c2a7a81962f3663e3"
integrity sha512-u+1Q0dJG5BidgUTpz9CU16yoHTt/oApFDQ3mbvHwSDgMjU7aGqy0q8ZQyaZyaNxdwRKTD872Ux3Twc6//sWA+Q==
dependencies:
chalk "^2.4.2"
date-fns "^2.0.1"
lodash "^4.17.15"
read-pkg "^4.0.1"
rxjs "^6.5.2"
chalk "^4.1.0"
date-fns "^2.16.1"
lodash "^4.17.21"
read-pkg "^5.2.0"
rxjs "^6.6.3"
spawn-command "^0.0.2-1"
supports-color "^6.1.0"
supports-color "^8.1.0"
tree-kill "^1.2.2"
yargs "^13.3.0"
yargs "^16.2.0"
config-chain@^1.1.11:
version "1.1.12"
@ -7919,9 +7999,9 @@ csstype@^2.5.2, csstype@^2.5.7:
integrity sha512-FNeiVKudquehtR3t9TRRnsHL+lJhuHF5Zn9dt01jpojlurLEPDhhEtUkWmAUJ7/fOLaLG4dCDEnUsR0N1rZSsg==
csstype@^3.0.2:
version "3.0.6"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.6.tgz#865d0b5833d7d8d40f4e5b8a6d76aea3de4725ef"
integrity sha512-+ZAmfyWMT7TiIlzdqJgjMb7S4f1beorDbWbsocyK4RaiqA5RTX3K14bnBWmmA9QEM0gRdsjyyrEmcyga8Zsxmw==
version "3.0.7"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.7.tgz#2a5fb75e1015e84dd15692f71e89a1450290950b"
integrity sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g==
currency-flags@2.1.2:
version "2.1.2"
@ -7969,15 +8049,10 @@ data-urls@^2.0.0:
whatwg-mimetype "^2.3.0"
whatwg-url "^8.0.0"
date-fns@2.16.1:
version "2.16.1"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.16.1.tgz#05775792c3f3331da812af253e1a935851d3834b"
integrity sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ==
date-fns@^2.0.1:
version "2.17.0"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.17.0.tgz#afa55daea539239db0a64e236ce716ef3d681ba1"
integrity sha512-ZEhqxUtEZeGgg9eHNSOAJ8O9xqSgiJdrL0lzSSfMF54x6KXWJiOH/xntSJ9YomJPrYH/p08t6gWjGWq1SDJlSA==
date-fns@^2.16.1, date-fns@^2.20.2:
version "2.20.2"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.20.2.tgz#7f05d1275e1e43c3bdde5998201920098e19c6a1"
integrity sha512-QS0Z8SD/ALhKFvhtU4Fhz+1crsI7fPzBquXmdWay33KJPEU7btro2hnmmErpQRmt2D624B1lbjXQKDUMLnQTmQ==
debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.8, debug@^2.6.9:
version "2.6.9"
@ -8625,9 +8700,9 @@ electron-is-dev@^1.2.0:
integrity sha512-R1oD5gMBPS7PVU8gJwH6CtT0e6VSoD0+SzSnYpNm+dBkcijgA+K7VAMHDfnRq/lkKPZArpzplTW6jfiMYosdzw==
electron-log@^4.3.0:
version "4.3.2"
resolved "https://registry.yarnpkg.com/electron-log/-/electron-log-4.3.2.tgz#213334c69f0498fac677a7a73eae4a61fb69949e"
integrity sha512-PJPWE8JDzQ137UlxX9K917nI8GTcwgiJpE2PMPXZo+I6C4AaZU+JWQ3lW5NjQ1Lg8Qk8qbze+Ly0yAiqhbmpeA==
version "4.3.4"
resolved "https://registry.yarnpkg.com/electron-log/-/electron-log-4.3.4.tgz#97e991dcd653e759e14eb2ae5d6ba4440f50afd8"
integrity sha512-Cd6xZ9if2J4NG+PNoi3cARAYoanbM4ddpod0faaL5LIhmwuSdxP9XH95C9SgTpHMqklbg8u3CFh1yqiaqo2Bng==
electron-notarize@1.0.0:
version "1.0.0"
@ -9141,13 +9216,6 @@ eslint-plugin-react@^7.21.5:
resolve "^1.18.1"
string.prototype.matchall "^4.0.2"
eslint-plugin-sort-destructure-keys@^1.3.5:
version "1.3.5"
resolved "https://registry.yarnpkg.com/eslint-plugin-sort-destructure-keys/-/eslint-plugin-sort-destructure-keys-1.3.5.tgz#c6f45c3e58d4435564025a6ca5f4a838010800fd"
integrity sha512-JmVpidhDsLwZsmRDV7Tf/vZgOAOEQGkLtwToSvX5mD8fuWYS/xkgMRBsalW1fGlc8CgJJwnzropt4oMQ7YCHLg==
dependencies:
natural-compare-lite "^1.4.0"
eslint-plugin-testing-library@^3.9.2:
version "3.10.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-testing-library/-/eslint-plugin-testing-library-3.10.1.tgz#4dd02306d601c3238fdabf1d1dbc5f2a8e85d531"
@ -9803,12 +9871,12 @@ ethereumjs-util@^6.0.0, ethereumjs-util@^6.1.0:
ethjs-util "0.1.6"
rlp "^2.2.3"
ethereumjs-util@^7.0.2, ethereumjs-util@^7.0.3:
version "7.0.8"
resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.0.8.tgz#5258762b7b17e3d828e41834948363ff0a703ffd"
integrity sha512-JJt7tDpCAmDPw/sGoFYeq0guOVqT3pTE9xlEbBmc/nlCij3JRCoS2c96SQ6kXVHOT3xWUNLDm5QCJLQaUnVAtQ==
ethereumjs-util@^7.0.2, ethereumjs-util@^7.0.3, ethereumjs-util@^7.0.8:
version "7.0.10"
resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.0.10.tgz#5fb7b69fa1fda0acc59634cf39d6b0291180fc1f"
integrity sha512-c/xThw6A+EAnej5Xk5kOzFzyoSnw0WX0tSlZ6pAsfGVvQj3TItaDg9b1+Fz1RJXA+y2YksKwQnuzgt1eY6LKzw==
dependencies:
"@types/bn.js" "^4.11.3"
"@types/bn.js" "^5.1.0"
bn.js "^5.1.2"
create-hash "^1.1.2"
ethereum-cryptography "^0.1.3"
@ -9975,6 +10043,11 @@ execa@^4.0.0, execa@^4.1.0:
signal-exit "^3.0.2"
strip-final-newline "^2.0.0"
exenv@^1.2.0:
version "1.2.2"
resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
integrity sha1-KueOhdmJQVhnCwPUe+wfA72Ru50=
exit-on-epipe@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692"
@ -14664,11 +14737,6 @@ native-url@^0.2.6:
dependencies:
querystring "^0.2.0"
natural-compare-lite@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4"
integrity sha1-F7CVgZiJef3a/gIB6TG6kzyWy7Q=
natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
@ -16879,7 +16947,7 @@ qr.js@0.0.0:
resolved "https://registry.yarnpkg.com/qr.js/-/qr.js-0.0.0.tgz#cace86386f59a0db8050fa90d9b6b0e88a1e364f"
integrity sha1-ys6GOG9ZoNuAUPqQ2baw6IoeNk8=
qrcode.react@1.0.1:
qrcode.react@1.0.1, qrcode.react@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/qrcode.react/-/qrcode.react-1.0.1.tgz#2834bb50e5e275ffe5af6906eff15391fe9e38a5"
integrity sha512-8d3Tackk8IRLXTo67Y+c1rpaiXjoz/Dd2HpcMdW//62/x8J1Nbho14Kh8x974t9prsLHN6XqVgcnRiBGFptQmg==
@ -17219,6 +17287,15 @@ react-dom@^16.8.3:
prop-types "^15.6.2"
scheduler "^0.19.1"
react-dom@^17.0.1:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23"
integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
scheduler "^0.20.2"
react-draggable@^4.0.3:
version "4.4.3"
resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.4.3.tgz#0727f2cae5813e36b0e4962bf11b2f9ef2b406f3"
@ -17249,10 +17326,10 @@ react-final-form-listeners@^1.0.2:
dependencies:
"@babel/runtime" "^7.12.5"
react-final-form@^6.5.2:
version "6.5.2"
resolved "https://registry.yarnpkg.com/react-final-form/-/react-final-form-6.5.2.tgz#d04d1eb7d92eabc6f6c35206bb0eebfc4bfd924b"
integrity sha512-c5l45FYOoxtfpvsvMFh3w2WW8KNxbuebBUrM16rUrooQkewTs0Zahmv0TuKFX5jsC9BKn5Fo84j3ZVXQdURS4w==
react-final-form@^6.5.3:
version "6.5.3"
resolved "https://registry.yarnpkg.com/react-final-form/-/react-final-form-6.5.3.tgz#b60955837fe9d777456ae9d9c48e3e2f21547d29"
integrity sha512-FCs6GC0AMWJl2p6YX7kM+a0AvuSLAZUgbVNtRBskOs4g984t/It0qGtx51O+9vgqnqk6JyoxmIzxKMq+7ch/vg==
dependencies:
"@babel/runtime" "^7.12.1"
@ -17329,7 +17406,7 @@ react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-i
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339"
integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==
react-lifecycles-compat@^3.0.4:
react-lifecycles-compat@^3.0.0, react-lifecycles-compat@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
@ -17344,6 +17421,16 @@ react-media@^1.10.0:
json2mq "^0.2.0"
prop-types "^15.5.10"
react-modal@^3.12.1:
version "3.12.1"
resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.12.1.tgz#38c33f70d81c33d02ff1ed115530443a3dc2afd3"
integrity sha512-WGuXn7Fq31PbFJwtWmOk+jFtGC7E9tJVbFX0lts8ZoS5EPi9+WWylUJWLKKVm3H4GlQ7ZxY7R6tLlbSIBQ5oZA==
dependencies:
exenv "^1.2.0"
prop-types "^15.5.10"
react-lifecycles-compat "^3.0.0"
warning "^4.0.3"
react-popper-tooltip@^2.8.3:
version "2.11.1"
resolved "https://registry.yarnpkg.com/react-popper-tooltip/-/react-popper-tooltip-2.11.1.tgz#3c4bdfd8bc10d1c2b9a162e859bab8958f5b2644"
@ -17373,12 +17460,13 @@ react-qr-reader@^2.2.1:
prop-types "^15.7.2"
webrtc-adapter "^7.2.1"
react-redux@7.2.2:
version "7.2.2"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.2.tgz#03862e803a30b6b9ef8582dadcc810947f74b736"
integrity sha512-8+CQ1EvIVFkYL/vu6Olo7JFLWop1qRUeb46sGtIMDCSpgwPQq8fPLpirIB0iTqFe9XYEFPHssdX8/UwN6pAkEA==
react-redux@7.2.3:
version "7.2.3"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.3.tgz#4c084618600bb199012687da9e42123cca3f0be9"
integrity sha512-ZhAmQ1lrK+Pyi0ZXNMUZuYxYAZd59wFuVDGUt536kSGdD0ya9Q7BfsE95E3TsFLE3kOSFp5m6G5qbatE+Ic1+w==
dependencies:
"@babel/runtime" "^7.12.1"
"@types/react-redux" "^7.1.16"
hoist-non-react-statics "^3.3.2"
loose-envify "^1.4.0"
prop-types "^15.7.2"
@ -17549,6 +17637,14 @@ react@^16.8.3:
object-assign "^4.1.1"
prop-types "^15.6.2"
react@^17.0.1:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
read-config-file@6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/read-config-file/-/read-config-file-6.0.0.tgz#224b5dca6a5bdc1fb19e63f89f342680efdb9299"
@ -17603,15 +17699,6 @@ read-pkg@^3.0.0:
normalize-package-data "^2.3.2"
path-type "^3.0.0"
read-pkg@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-4.0.1.tgz#963625378f3e1c4d48c85872b5a6ec7d5d093237"
integrity sha1-ljYlN48+HE1IyFhytabsfV0JMjc=
dependencies:
normalize-package-data "^2.3.2"
parse-json "^4.0.0"
pify "^3.0.0"
read-pkg@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc"
@ -18336,10 +18423,10 @@ rustbn.js@~0.2.0:
resolved "https://registry.yarnpkg.com/rustbn.js/-/rustbn.js-0.2.0.tgz#8082cb886e707155fd1cb6f23bd591ab8d55d0ca"
integrity sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==
rxjs@^6.1.0, rxjs@^6.4.0, rxjs@^6.5.2, rxjs@^6.6.0, rxjs@^6.6.3, rxjs@^6.6.6:
version "6.6.6"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.6.tgz#14d8417aa5a07c5e633995b525e1e3c0dec03b70"
integrity sha512-/oTwee4N4iWzAMAL9xdGKjkEHmIwupR3oXbQjCKywF1BeFohswF3vZdogbmEF6pZkOsXTzWkrZszrWpQTByYVg==
rxjs@^6.1.0, rxjs@^6.4.0, rxjs@^6.6.0, rxjs@^6.6.3, rxjs@^6.6.7:
version "6.6.7"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9"
integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==
dependencies:
tslib "^1.9.0"
@ -18464,6 +18551,14 @@ scheduler@^0.19.1:
loose-envify "^1.1.0"
object-assign "^4.1.1"
scheduler@^0.20.2:
version "0.20.2"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91"
integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
schema-utils@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770"
@ -18588,10 +18683,10 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
semver@^7.2.1, semver@^7.3.2, semver@^7.3.4:
version "7.3.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97"
integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==
semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5:
version "7.3.5"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
dependencies:
lru-cache "^6.0.0"
@ -18733,7 +18828,7 @@ setprototypeof@1.1.1:
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
sha.js@^2.4.0, sha.js@^2.4.8:
sha.js@^2.4.0, sha.js@^2.4.11, sha.js@^2.4.8:
version "2.4.11"
resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7"
integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==
@ -19215,9 +19310,9 @@ sshpk@^1.7.0:
tweetnacl "~0.14.0"
ssri@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8"
integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==
version "6.0.2"
resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.2.tgz#157939134f20464e7301ddba3e90ffa8f7728ac5"
integrity sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==
dependencies:
figgy-pudding "^3.5.1"
@ -19668,6 +19763,13 @@ supports-color@^7.0.0, supports-color@^7.1.0:
dependencies:
has-flag "^4.0.0"
supports-color@^8.1.0:
version "8.1.1"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
dependencies:
has-flag "^4.0.0"
supports-hyperlinks@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz#f663df252af5f37c5d49bbd7eeefa9e0b9e59e47"
@ -20903,14 +21005,14 @@ w3c-xmlserializer@^2.0.0:
dependencies:
xml-name-validator "^3.0.0"
wait-on@5.2.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-5.2.1.tgz#05b66fcb4d7f5da01537f03e7cf96e8836422996"
integrity sha512-H2F986kNWMU9hKlI9l/ppO6tN8ZSJd35yBljMLa1/vjzWP++Qh6aXyt77/u7ySJFZQqBtQxnvm/xgG48AObXcw==
wait-on@^5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-5.3.0.tgz#584e17d4b3fe7b46ac2b9f8e5e102c005c2776c7"
integrity sha512-DwrHrnTK+/0QFaB9a8Ol5Lna3k7WvUR4jzSKmz0YaPBpuN2sACyiPVKVfj6ejnjcajAcvn3wlbTyMIn9AZouOg==
dependencies:
axios "^0.21.1"
joi "^17.3.0"
lodash "^4.17.20"
lodash "^4.17.21"
minimist "^1.2.5"
rxjs "^6.6.3"
@ -22521,7 +22623,7 @@ yargs-unparser@1.6.1:
is-plain-obj "^1.1.0"
yargs "^14.2.3"
yargs@13.3.2, yargs@^13.2.4, yargs@^13.3.0, yargs@^13.3.2:
yargs@13.3.2, yargs@^13.2.4, yargs@^13.3.2:
version "13.3.2"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd"
integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==