diff --git a/.env.example b/.env.example index 33d8a508..266bbc27 100644 --- a/.env.example +++ b/.env.example @@ -26,3 +26,7 @@ REACT_APP_APP_VERSION=$npm_package_version # For Apps REACT_APP_GNOSIS_APPS_URL=https://safe-apps.staging.gnosisdev.com + +# Contracts Addresses +REACT_APP_SPENDING_LIMIT_MODULE_ADDRESS=0x9e9Bf12b5a66c0f0A7435835e0365477E121B110 + diff --git a/.prettierignore b/.prettierignore index 0b56bd82..5660707c 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,7 +1,7 @@ !.eslintrc.js build -config -contracts +/config +/contracts flow-typed flow-typed/npm migrations @@ -9,5 +9,5 @@ node_modules public scripts src/assets -src/config +src/types/contracts test \ No newline at end of file diff --git a/package.json b/package.json index 83c1d90b..359a7976 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "safe-react", - "version": "2.15.1", + "version": "2.16.0", "description": "Allowing crypto users manage funds in a safer way", "website": "https://github.com/gnosis/safe-react#readme", "bugs": { @@ -16,7 +16,7 @@ "email": "safe@gnosis.io" }, "main": "public/electron.js", - "postinstall": "electron-builder install-app-deps", + "postinstall": "patch-package electron-builder install-app-deps", "scripts": { "analyze": "source-map-explorer 'build/static/js/*.js'", "build-desktop": "cross-env REACT_APP_BUILD_FOR_DESKTOP=true REACT_APP_ENV=production yarn build-mainnet", @@ -26,11 +26,12 @@ "electron-build": "electron-builder --mac --windows --linux", "electron-dev": "concurrently \"BROWSER=none yarn start\" \"wait-on http://localhost:3000 && electron .\"", "format:staged": "lint-staged", - "generate-types": "yarn generate-types:contracts", + "generate-types": "yarn generate-types:contracts && yarn generate-types:spendingLimit", "generate-types:contracts": "cross-env typechain --target=web3-v1 --outDir './src/types/contracts' './node_modules/@gnosis.pm/safe-contracts/build/contracts/*.json'", + "generate-types:spendingLimit": "cross-env typechain --target=web3-v1 --outDir './src/types/contracts' ./src/logic/contracts/artifacts/*.json", "lint:check": "eslint './src/**/*.{js,jsx,ts,tsx}'", "lint:fix": "yarn lint:check --fix", - "postinstall": "electron-builder install-app-deps && yarn generate-types", + "postinstall": "patch-package && electron-builder install-app-deps && yarn generate-types", "preelectron-pack": "yarn build", "prettier:check": "yarn prettier --check", "prettier:fix": "yarn prettier --write", @@ -168,16 +169,16 @@ "dependencies": { "@gnosis.pm/safe-apps-sdk": "https://github.com/gnosis/safe-apps-sdk.git#3f0689f", "@gnosis.pm/safe-contracts": "1.1.1-dev.2", - "@gnosis.pm/safe-react-components": "https://github.com/gnosis/safe-react-components.git#03ff672d6f73366297986d58631f9582fe2ed4a3", + "@gnosis.pm/safe-react-components": "https://github.com/gnosis/safe-react-components.git#ff29c3c", "@gnosis.pm/util-contracts": "2.0.6", - "@ledgerhq/hw-transport-node-hid-singleton": "5.29.0", + "@ledgerhq/hw-transport-node-hid-singleton": "5.30.0", "@material-ui/core": "4.11.0", "@material-ui/icons": "4.9.1", "@material-ui/lab": "4.0.0-alpha.56", "@openzeppelin/contracts": "3.1.0", - "@sentry/react": "^5.27.3", - "@sentry/tracing": "^5.27.3", - "@truffle/contract": "4.2.28", + "@sentry/react": "^5.27.0", + "@sentry/tracing": "^5.27.0", + "@truffle/contract": "4.2.30", "async-sema": "^3.1.0", "axios": "0.21.0", "bignumber.js": "9.0.1", @@ -209,25 +210,25 @@ "material-ui-search-bar": "^1.0.0", "notistack": "https://github.com/gnosis/notistack.git#v0.9.4", "qrcode.react": "1.0.0", - "query-string": "6.13.6", + "query-string": "6.13.7", "react": "16.13.1", "react-dom": "16.13.1", "react-final-form": "^6.5.2", "react-final-form-listeners": "^1.0.2", - "react-ga": "3.2.0", + "react-ga": "3.2.1", "react-hot-loader": "4.13.0", "react-qr-reader": "^2.2.1", - "react-redux": "7.2.1", + "react-redux": "7.2.2", "react-router-dom": "5.2.0", "react-scripts": "^3.4.3", - "react-window": "^1.8.5", + "react-window": "^1.8.6", "recompose": "^0.30.0", "redux": "4.0.5", "redux-actions": "^2.6.5", "redux-thunk": "^2.3.0", "reselect": "^4.0.0", "semver": "7.3.2", - "styled-components": "^5.2.0", + "styled-components": "^5.2.1", "web3": "1.2.11", "web3-core": "^1.2.11", "web3-eth-contract": "^1.2.11", @@ -238,7 +239,7 @@ "@storybook/addon-actions": "^5.3.19", "@storybook/addon-links": "^5.3.19", "@storybook/addons": "^5.3.19", - "@storybook/preset-create-react-app": "^3.1.4", + "@storybook/preset-create-react-app": "^3.1.5", "@storybook/react": "^5.3.19", "@testing-library/jest-dom": "5.11.5", "@testing-library/react": "10.4.9", @@ -258,24 +259,25 @@ "cross-env": "^7.0.2", "dotenv": "^8.2.0", "dotenv-expand": "^5.1.0", - "electron": "9.3.3", + "electron": "^9.3.3", "electron-builder": "22.9.1", "electron-notarize": "1.0.0", "eslint": "6.8.0", - "eslint-config-prettier": "6.14.0", - "eslint-plugin-import": "2.22.1", + "eslint-config-prettier": "^6.14.0", + "eslint-plugin-import": "^2.22.1", "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", + "eslint-plugin-sort-destructure-keys": "^1.3.5", "ethereumjs-abi": "0.6.8", "husky": "^4.3.0", "lint-staged": "^10.5.1", "node-sass": "^4.14.1", - "prettier": "2.1.2", + "patch-package": "^6.2.2", + "postinstall-postinstall": "^2.1.0", + "prettier": "^2.1.2", "react-app-rewired": "^2.1.6", - "react-docgen-typescript-loader": "^3.7.2", - "typechain": "^2.0.0", + "typechain": "^4.0.0", "typescript": "4.0.5", "wait-on": "5.2.0" } diff --git a/patches/web3-eth+1.2.11.patch b/patches/web3-eth+1.2.11.patch new file mode 100644 index 00000000..9de3c1ca --- /dev/null +++ b/patches/web3-eth+1.2.11.patch @@ -0,0 +1,19 @@ +diff --git a/node_modules/web3-eth/src/getNetworkType.js b/node_modules/web3-eth/src/getNetworkType.js +index 3be3a20..88edbd9 100644 +--- a/node_modules/web3-eth/src/getNetworkType.js ++++ b/node_modules/web3-eth/src/getNetworkType.js +@@ -63,6 +63,14 @@ var getNetworkType = function (callback) { + id === 42) { + returnValue = 'kovan'; + } ++ if (genesis.hash === '0x0b6d3e680af2fc525392c720666cce58e3d8e6fe75ba4b48cb36bcc69039229b' && ++ id === 246) { ++ returnValue = 'energyWebChain'; ++ } ++ if (genesis.hash === '0xebd8b413ca7b7f84a8dd20d17519ce2b01954c74d94a0a739a3e416abe0e43e5' && ++ id === 73799) { ++ returnValue = 'volta'; ++ } + + if (_.isFunction(callback)) { + callback(null, returnValue); diff --git a/patches/web3-eth-ens+1.2.11.patch b/patches/web3-eth-ens+1.2.11.patch new file mode 100644 index 00000000..ea9249fb --- /dev/null +++ b/patches/web3-eth-ens+1.2.11.patch @@ -0,0 +1,15 @@ +diff --git a/node_modules/web3-eth-ens/src/config.js b/node_modules/web3-eth-ens/src/config.js +index b12e5f5..e0abf2d 100644 +--- a/node_modules/web3-eth-ens/src/config.js ++++ b/node_modules/web3-eth-ens/src/config.js +@@ -30,7 +30,9 @@ var config = { + main: "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", + ropsten: "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", + rinkeby: "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", +- goerli: "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e" ++ goerli: "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", ++ energyWebChain: "0x0A6d64413c07E10E890220BBE1c49170080C6Ca0", ++ volta: "0xd7CeF70Ba7efc2035256d828d5287e2D285CD1ac", + }, + // These ids obtained at ensdomains docs: + // https://docs.ens.domains/contract-developer-guide/writing-a-resolver diff --git a/public/electron.js b/public/electron.js index 140a1f26..ae9368b8 100644 --- a/public/electron.js +++ b/public/electron.js @@ -85,7 +85,7 @@ function getOpenedWindow(url, options) { function createWindow(port = DEFAULT_PORT) { mainWindow = new BrowserWindow({ show: false, - width: 1024, + width: 1366, height: 768, webPreferences: { preload: path.join(__dirname, '../scripts/preload.js'), diff --git a/src/routes/safe/components/Transactions/TxsTable/TxType/assets/appsIcon.svg b/src/assets/icons/apps.svg similarity index 100% rename from src/routes/safe/components/Transactions/TxsTable/TxType/assets/appsIcon.svg rename to src/assets/icons/apps.svg diff --git a/src/components/AppLayout/Sidebar/SafeHeader/index.tsx b/src/components/AppLayout/Sidebar/SafeHeader/index.tsx index 16a0268d..ee1503d4 100644 --- a/src/components/AppLayout/Sidebar/SafeHeader/index.tsx +++ b/src/components/AppLayout/Sidebar/SafeHeader/index.tsx @@ -130,10 +130,13 @@ const SafeHeader = ({ return ( <> + {/* Network */} {networkInfo.label} + + {/* Identicon */} @@ -142,6 +145,7 @@ const SafeHeader = ({ + {/* SafeInfo */} {safeName} diff --git a/src/components/AppLayout/Sidebar/index.tsx b/src/components/AppLayout/Sidebar/index.tsx index 673b994d..b01876a8 100644 --- a/src/components/AppLayout/Sidebar/index.tsx +++ b/src/components/AppLayout/Sidebar/index.tsx @@ -16,7 +16,7 @@ const HelpContainer = styled.div` const HelpCenterLink = styled.a` height: 30px; width: 166px; - padding: 6px 0 0 16px; + padding: 6px 0 8px 16px; margin: 14px 0px; text-decoration: none; display: block; diff --git a/src/components/AppLayout/Sidebar/useSidebarItems.tsx b/src/components/AppLayout/Sidebar/useSidebarItems.tsx index 4cf8e76b..c31b4cbe 100644 --- a/src/components/AppLayout/Sidebar/useSidebarItems.tsx +++ b/src/components/AppLayout/Sidebar/useSidebarItems.tsx @@ -19,7 +19,7 @@ const useSidebarItems = (): ListItemType[] => { } return useMemo((): ListItemType[] => { - if (!matchSafe || !matchSafeWithAddress) { + if (!matchSafe || !matchSafeWithAddress || !featuresEnabled) { return [] } @@ -63,7 +63,7 @@ const useSidebarItems = (): ListItemType[] => { }, ...safeSidebar, ] - }, [matchSafe, matchSafeWithAction, matchSafeWithAddress, safeAppsEnabled]) + }, [matchSafe, matchSafeWithAction, matchSafeWithAddress, safeAppsEnabled, featuresEnabled]) } export { useSidebarItems } diff --git a/src/components/AppLayout/index.tsx b/src/components/AppLayout/index.tsx index 4ac72c9e..1426788a 100644 --- a/src/components/AppLayout/index.tsx +++ b/src/components/AppLayout/index.tsx @@ -6,53 +6,62 @@ import Header from './Header' import Footer from './Footer' import Sidebar from './Sidebar' -const Grid = styled.div` - height: 100%; - overflow: auto; +const Container = styled.div` + height: 100vh; + width: 100vw; + display: flex; + flex-direction: column; + background-color: ${({ theme }) => theme.colors.background}; - display: grid; - grid-template-columns: 200px 1fr; - grid-template-rows: 54px 1fr; - grid-template-areas: - 'topbar topbar' - 'sidebar body'; ` -const GridTopbarWrapper = styled.nav` +const HeaderWrapper = styled.nav` + height: 54px; + width: 100%; + z-index: 1; + background-color: white; - box-shadow: 0 2px 4px 0 rgba(212, 212, 211, 0.59); - border-bottom: 2px solid ${({ theme }) => theme.colors.separator}; - z-index: 999; - grid-area: topbar; + box-shadow: 0 0 4px 0 rgba(212, 212, 211, 0.59); ` -const GridSidebarWrapper = styled.aside` - width: 200px; - padding: 62px 8px 0 8px; +const BodyWrapper = styled.div` + height: calc(100% - 54px); + width: 100%; + display: flex; + flex-direction: row; +` + +const SidebarWrapper = styled.aside` height: 100%; + width: 200px; + display: flex; + flex-direction: column; + z-index: 1; + + padding: 8px 8px 0 8px; background-color: ${({ theme }) => theme.colors.white}; border-right: 2px solid ${({ theme }) => theme.colors.separator}; +` + +const ContentWrapper = styled.section` + width: 100%; display: flex; flex-direction: column; - box-sizing: border-box; - position: fixed; - grid-area: sidebar; -` + overflow-x: auto; -const GridBodyWrapper = styled.section` - margin: 0 16px 0 16px; - grid-area: body; - display: flex; - flex-direction: column; - align-content: stretch; -` + padding: 0 16px; -export const BodyWrapper = styled.div` - flex: 1 100%; -` + > :nth-child(1) { + flex-grow: 1; + width: 100%; + align-items: center; + justify-content: center; + } -export const FooterWrapper = styled.footer` - margin: 0 16px; + > :nth-child(2) { + width: 100%; + height: 59px; + } ` type Props = { @@ -77,29 +86,29 @@ const Layout: React.FC = ({ children, sidebarItems, }): React.ReactElement => ( - - + +
- - - - - - {children} - + + + + + + +
{children}