From 352461658bab751f5076eb0d96c1f413f695c27f Mon Sep 17 00:00:00 2001 From: Daniel Sanchez Date: Wed, 17 Mar 2021 20:04:00 +0100 Subject: [PATCH 01/15] Release v3.1.3 - Desktop app (#2045) * Update release desktop app github action * Restore yarn install step for desktop build * Add linux deps for Ledger build in desktop workflow Update electron to latest v9 * Push back ubuntu version for desktop build * Set ubuntu 18 for linux desktop app * Update Desktop App signature * Set v3.1.3 * Fix AWS credentials configuration for Volta, xDai and EWC * Remove explicit aws credentials for all networks --- .github/workflows/deploy-ewc.yml | 16 +++-- .github/workflows/deploy-rinkeby.yml | 4 +- .github/workflows/deploy-volta.yml | 17 +++--- .github/workflows/deploy-xdai.yml | 16 +++-- .github/workflows/release-mainnet-desktop.yml | 29 +++++---- public/electron.js | 6 +- yarn.lock | 59 +++---------------- 7 files changed, 51 insertions(+), 96 deletions(-) diff --git a/.github/workflows/deploy-ewc.yml b/.github/workflows/deploy-ewc.yml index 2081c697..39aaf20d 100644 --- a/.github/workflows/deploy-ewc.yml +++ b/.github/workflows/deploy-ewc.yml @@ -76,12 +76,17 @@ jobs: REACT_APP_INTERCOM_ID: ${{ secrets.REACT_APP_INTERCOM_ID }} REACT_APP_IPFS_GATEWAY: ${{ secrets.REACT_APP_IPFS_GATEWAY }} + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_DEFAULT_REGION }} + # Script to deploy Pull Requests - run: bash ./scripts/github/deploy_pull_request.sh if: success() && github.event.number env: - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} PR_NUMBER: ${{ github.event.number }} REVIEW_BUCKET_NAME: ${{ secrets.AWS_REVIEW_BUCKET_NAME }} REACT_APP_NETWORK: ${{ env.REACT_APP_NETWORK }} @@ -98,13 +103,6 @@ jobs: env: REVIEW_FEATURE_URL: https://pr${{ github.event.number }}--${{ env.REPO_NAME_ALPHANUMERIC }}.review.gnosisdev.com - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v1 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: ${{ secrets.AWS_DEFAULT_REGION }} - # Script to deploy to development environment # EWC build is never created in development branch diff --git a/.github/workflows/deploy-rinkeby.yml b/.github/workflows/deploy-rinkeby.yml index 9dceb243..9bc51a03 100644 --- a/.github/workflows/deploy-rinkeby.yml +++ b/.github/workflows/deploy-rinkeby.yml @@ -38,7 +38,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Remove broken apt repos [Ubuntu] - if: matrix.os == 'ubuntu-latest' + if: ${{ matrix.os }} == 'ubuntu-latest' run: | for apt_file in `grep -lr microsoft /etc/apt/sources.list.d/`; do sudo rm $apt_file; done - uses: actions/checkout@v2 @@ -91,8 +91,6 @@ jobs: - run: bash ./scripts/github/deploy_pull_request.sh if: success() && github.event.number env: - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} PR_NUMBER: ${{ github.event.number }} REVIEW_BUCKET_NAME: ${{ secrets.AWS_REVIEW_BUCKET_NAME }} REACT_APP_NETWORK: ${{ env.REACT_APP_NETWORK }} diff --git a/.github/workflows/deploy-volta.yml b/.github/workflows/deploy-volta.yml index 6f562e39..23f517c3 100644 --- a/.github/workflows/deploy-volta.yml +++ b/.github/workflows/deploy-volta.yml @@ -79,12 +79,17 @@ jobs: REACT_APP_INTERCOM_ID: ${{ secrets.REACT_APP_INTERCOM_ID }} REACT_APP_IPFS_GATEWAY: ${{ secrets.REACT_APP_IPFS_GATEWAY }} + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_DEFAULT_REGION }} + # Script to deploy Pull Requests - run: bash ./scripts/github/deploy_pull_request.sh if: success() && github.event.number env: - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} PR_NUMBER: ${{ github.event.number }} REVIEW_BUCKET_NAME: ${{ secrets.AWS_REVIEW_BUCKET_NAME }} REACT_APP_NETWORK: ${{ env.REACT_APP_NETWORK }} @@ -101,14 +106,6 @@ jobs: env: REVIEW_FEATURE_URL: https://pr${{ github.event.number }}--${{ env.REPO_NAME_ALPHANUMERIC }}.review.gnosisdev.com - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v1 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: ${{ secrets.AWS_DEFAULT_REGION }} - - # Script to deploy to development environment # Volta build is never created in development branch diff --git a/.github/workflows/deploy-xdai.yml b/.github/workflows/deploy-xdai.yml index 1aff151d..bedc557c 100644 --- a/.github/workflows/deploy-xdai.yml +++ b/.github/workflows/deploy-xdai.yml @@ -79,12 +79,17 @@ jobs: REACT_APP_INTERCOM_ID: ${{ secrets.REACT_APP_INTERCOM_ID }} REACT_APP_IPFS_GATEWAY: ${{ secrets.REACT_APP_IPFS_GATEWAY }} + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_DEFAULT_REGION }} + # Script to deploy Pull Requests - run: bash ./scripts/github/deploy_pull_request.sh if: success() && github.event.number env: - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} PR_NUMBER: ${{ github.event.number }} REVIEW_BUCKET_NAME: ${{ secrets.AWS_REVIEW_BUCKET_NAME }} REACT_APP_NETWORK: ${{ env.REACT_APP_NETWORK }} @@ -101,13 +106,6 @@ jobs: env: REVIEW_FEATURE_URL: https://pr${{ github.event.number }}--${{ env.REPO_NAME_ALPHANUMERIC }}.review.gnosisdev.com - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v1 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: ${{ secrets.AWS_DEFAULT_REGION }} - # Script to deploy to development environment # xDai build is never created in development branch diff --git a/.github/workflows/release-mainnet-desktop.yml b/.github/workflows/release-mainnet-desktop.yml index ac95cf22..c8556827 100644 --- a/.github/workflows/release-mainnet-desktop.yml +++ b/.github/workflows/release-mainnet-desktop.yml @@ -19,17 +19,18 @@ jobs: fail-fast: false max-parallel: 15 matrix: - os: [macos-latest, windows-latest, ubuntu-20.04] + os: [macos-latest, windows-latest, ubuntu-18.04] steps: - name: Check out Git repository uses: actions/checkout@v2 - - uses: actions/cache@v2 - with: - path: '**/node_modules' - key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} + # Linux build patches + - name: Install linux dependencies + if: startsWith(matrix.os, 'ubuntu') + run: sudo apt-get update && sudo apt-get install libudev-dev libusb-1.0-0-dev + # Windows build patches - name: Patch node gyp on windows to support Visual Studio 2019 if: startsWith(matrix.os, 'windows') shell: powershell @@ -41,18 +42,20 @@ jobs: run: | yarn global add node-gyp yarn config set node_gyp "$_\node_modules\node-gyp\bin\node-gyp.js" + + # Load node_modules cache action + - uses: actions/cache@v2 + with: + path: '**/node_modules' + key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} + - name: Install Node.js, NPM and Yarn uses: actions/setup-node@v2 with: node-version: 14 - - run: | - # Due to some dependencies yarn may randomly throw an error about invalid cache - # This approach is taken from https://github.com/yarnpkg/yarn/issues/7212#issuecomment-506155894 to fix the issue - # Another approach is to install with flag --network-concurrency 1, but this will make the installation pretty slow (default value is 8) - mkdir .yarncache - yarn install --cache-folder ./.yarncache --frozen-lockfile - rm -rf .yarncache - yarn cache clean + + - name: Run yarn install + run: yarn install --frozen-lockfile --network-concurrency 1 - name: Build/Release Desktop App env: diff --git a/public/electron.js b/public/electron.js index ac071d25..94a7bbf5 100644 --- a/public/electron.js +++ b/public/electron.js @@ -89,7 +89,9 @@ function createWindow(port = DEFAULT_PORT) { height: 768, webPreferences: { preload: path.join(__dirname, '../scripts/preload.js'), - allowRunningInsecureContent: true, + experimentalFeatures: true, + nodeIntegration: true, + // allowRunningInsecureContent: true, enableRemoteModule: true, nativeWindowOpen: true, // need to be set in order to display modal }, @@ -142,7 +144,7 @@ process.on('uncaughtException', function (error) { }) app.userAgentFallback = - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) old-airport-include/1.0.0 Chrome Electron/9.4.1 Safari/537.36' + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) old-airport-include/1.0.0 Chrome Electron/11.3.0 Safari/537.36' // We have one non-context-aware module in node_modules/usb. This is used by @ledgerhq/hw-transport-node-hid // This type of modules will be impossible to use after electron 10 diff --git a/yarn.lock b/yarn.lock index c22c0bf3..71abef68 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3503,7 +3503,12 @@ 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.12.6", "@types/node@^12.6.1": +"@types/node@^12.0.12": + 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== @@ -3756,18 +3761,6 @@ semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/experimental-utils@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.16.1.tgz#da7a396dc7d0e01922acf102b76efff17320b328" - integrity sha512-0Hm3LSlMYFK17jO4iY3un1Ve9x1zLNn4EM50Lia+0EV99NdbK+cn0er7HC7IvBA23mBg3P+8dUkMXy4leL33UQ== - dependencies: - "@types/json-schema" "^7.0.3" - "@typescript-eslint/scope-manager" "4.16.1" - "@typescript-eslint/types" "4.16.1" - "@typescript-eslint/typescript-estree" "4.16.1" - eslint-scope "^5.0.0" - eslint-utils "^2.0.0" - "@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" @@ -3801,14 +3794,6 @@ "@typescript-eslint/typescript-estree" "4.17.0" debug "^4.1.1" -"@typescript-eslint/scope-manager@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.16.1.tgz#244e2006bc60cfe46987e9987f4ff49c9e3f00d5" - integrity sha512-6IlZv9JaurqV0jkEg923cV49aAn8V6+1H1DRfhRcvZUrptQ+UtSKHb5kwTayzOYTJJ/RsYZdcvhOEKiBLyc0Cw== - dependencies: - "@typescript-eslint/types" "4.16.1" - "@typescript-eslint/visitor-keys" "4.16.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" @@ -3822,11 +3807,6 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-3.10.1.tgz#1d7463fa7c32d8a23ab508a803ca2fe26e758727" integrity sha512-+3+FCUJIahE9q0lDi1WleYzjCwJs5hIsbugIgnbB+dSCYUxl8L6PwmsyOPFZde2hc1DlTo/xnkOgiTLSyAbHiQ== -"@typescript-eslint/types@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.16.1.tgz#5ba2d3e38b1a67420d2487519e193163054d9c15" - integrity sha512-nnKqBwMgRlhzmJQF8tnFDZWfunXmJyuXj55xc8Kbfup4PbkzdoDXZvzN8//EiKR27J6vUSU8j4t37yUuYPiLqA== - "@typescript-eslint/types@4.17.0": version "4.17.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.17.0.tgz#f57d8fc7f31b348db946498a43050083d25f40ad" @@ -3846,19 +3826,6 @@ semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/typescript-estree@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.16.1.tgz#c2fc46b05a48fbf8bbe8b66a63f0a9ba04b356f1" - integrity sha512-m8I/DKHa8YbeHt31T+UGd/l8Kwr0XCTCZL3H4HMvvLCT7HU9V7yYdinTOv1gf/zfqNeDcCgaFH2BMsS8x6NvJg== - dependencies: - "@typescript-eslint/types" "4.16.1" - "@typescript-eslint/visitor-keys" "4.16.1" - debug "^4.1.1" - globby "^11.0.1" - is-glob "^4.0.1" - 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" @@ -3879,14 +3846,6 @@ dependencies: eslint-visitor-keys "^1.1.0" -"@typescript-eslint/visitor-keys@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.16.1.tgz#d7571fb580749fae621520deeb134370bbfc7293" - integrity sha512-s/aIP1XcMkEqCNcPQtl60ogUYjSM8FU2mq1O7y5cFf3Xcob1z1iXWNB6cC43Op+NGRTFgGolri6s8z/efA9i1w== - dependencies: - "@typescript-eslint/types" "4.16.1" - eslint-visitor-keys "^2.0.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" @@ -8889,9 +8848,9 @@ entities@~2.1.0: integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w== env-paths@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.0.tgz#cdca557dc009152917d6166e2febe1f039685e43" - integrity sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA== + version "2.2.1" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" + integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== errlop@^4.0.0: version "4.1.0" From a504ad495ab36d86ac6c5dc393465d97c20c2dbc Mon Sep 17 00:00:00 2001 From: Fernando Date: Thu, 18 Mar 2021 08:20:49 -0300 Subject: [PATCH 02/15] use `tokenBalance` for SendFunds modal (#2056) --- .../SendModal/screens/SendFunds/TokenSelectField/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/safe/components/Balances/SendModal/screens/SendFunds/TokenSelectField/index.tsx b/src/routes/safe/components/Balances/SendModal/screens/SendFunds/TokenSelectField/index.tsx index 454cb121..fbd745c4 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/SendFunds/TokenSelectField/index.tsx +++ b/src/routes/safe/components/Balances/SendModal/screens/SendFunds/TokenSelectField/index.tsx @@ -34,7 +34,7 @@ const SelectedToken = ({ tokenAddress, tokens }: SelectTokenProps): ReactElement ) : ( @@ -73,7 +73,7 @@ const TokenSelectField = ({ initialValue, isValid = true, tokens }: TokenSelectF From e2c11133772b1e3850a1e4e1b3ae0c3f6f5ffaaa Mon Sep 17 00:00:00 2001 From: Fernando Date: Thu, 18 Mar 2021 11:33:10 -0300 Subject: [PATCH 03/15] Remove asset and activeAssets references (#2058) --- src/logic/safe/store/actions/fetchSafe.ts | 1 - src/logic/safe/store/models/safe.ts | 2 -- src/logic/safe/store/reducer/safe.ts | 2 -- .../shouldSafeStoreBeUpdated.test.ts | 21 ------------------- .../utils/__tests__/tokenHelpers.test.ts | 2 +- 5 files changed, 1 insertion(+), 27 deletions(-) diff --git a/src/logic/safe/store/actions/fetchSafe.ts b/src/logic/safe/store/actions/fetchSafe.ts index d7dcba4f..5ffa962a 100644 --- a/src/logic/safe/store/actions/fetchSafe.ts +++ b/src/logic/safe/store/actions/fetchSafe.ts @@ -87,7 +87,6 @@ export const buildSafe = async ( featuresEnabled, balances: localSafe?.balances || Map(), latestIncomingTxBlock: 0, - activeAssets: Set(), activeTokens: Set(), modules, spendingLimits, diff --git a/src/logic/safe/store/models/safe.ts b/src/logic/safe/store/models/safe.ts index 38616f17..7fb02abf 100644 --- a/src/logic/safe/store/models/safe.ts +++ b/src/logic/safe/store/models/safe.ts @@ -34,7 +34,6 @@ export type SafeRecordProps = { modules?: ModulePair[] | null spendingLimits?: SpendingLimit[] | null activeTokens: Set - activeAssets: Set balances: Map nonce: number latestIncomingTxBlock: number @@ -54,7 +53,6 @@ const makeSafe = Record({ modules: [], spendingLimits: [], activeTokens: Set(), - activeAssets: Set(), balances: Map(), nonce: 0, latestIncomingTxBlock: 0, diff --git a/src/logic/safe/store/reducer/safe.ts b/src/logic/safe/store/reducer/safe.ts index 44112c4b..c75baef4 100644 --- a/src/logic/safe/store/reducer/safe.ts +++ b/src/logic/safe/store/reducer/safe.ts @@ -25,7 +25,6 @@ export const buildSafe = (storedSafe: SafeRecordProps): SafeRecordProps => { const addresses = storedSafe.owners.map((owner) => checksumAddress(owner.address)) const owners = buildOwnersFrom(Array.from(names), Array.from(addresses)) const activeTokens = Set(storedSafe.activeTokens) - const activeAssets = Set(storedSafe.activeAssets) const balances = Map(storedSafe.balances) return { @@ -33,7 +32,6 @@ export const buildSafe = (storedSafe: SafeRecordProps): SafeRecordProps => { owners, balances, activeTokens, - activeAssets, latestIncomingTxBlock: 0, modules: null, } diff --git a/src/logic/safe/utils/__tests__/shouldSafeStoreBeUpdated.test.ts b/src/logic/safe/utils/__tests__/shouldSafeStoreBeUpdated.test.ts index 51ca8521..0ed862bb 100644 --- a/src/logic/safe/utils/__tests__/shouldSafeStoreBeUpdated.test.ts +++ b/src/logic/safe/utils/__tests__/shouldSafeStoreBeUpdated.test.ts @@ -7,7 +7,6 @@ const getMockedOldSafe = ({ needsUpdate, balances, recurringUser, - assets, activeTokens, owners, featuresEnabled, @@ -30,8 +29,6 @@ const getMockedOldSafe = ({ } const mockedActiveTokenAddress1 = '0x36591cd3DA96b21Ac9ca54cFaf80fe45107294F1' const mockedActiveTokenAddress2 = '0x92aF97cbF10742dD2527ffaBA70e34C03CFFC2c1' - const mockedActiveAssetsAddress1 = '0x503ab2a6A70c6C6ec8b25a4C87C784e1c8f8e8CD' - const mockedActiveAssetsAddress2 = '0xfdd4E685361CB7E89a4D27e03DCd0001448d731F' return { name: name || 'MockedSafe', @@ -42,7 +39,6 @@ const getMockedOldSafe = ({ modules: modules || [], spendingLimits: spendingLimits || [], activeTokens: activeTokens || Set([mockedActiveTokenAddress1, mockedActiveTokenAddress2]), - assets: assets || Set([mockedActiveAssetsAddress1, mockedActiveAssetsAddress2]), balances: balances || Map({ @@ -198,23 +194,6 @@ describe('shouldSafeStoreBeUpdated', () => { // Then expect(expectedResult).toEqual(true) }) - it(`Given an old activeAssets list and a new activeAssets list for the safe, should return true`, () => { - // given - const mockedActiveTokenAddress1 = '0x36591cd3DA96b21Ac9ca54cFaf80fe45107294F1' - const mockedActiveTokenAddress2 = '0x92aF97cbF10742dD2527ffaBA70e34C03CFFC2c1' - const oldActiveAssets = Set([mockedActiveTokenAddress1, mockedActiveTokenAddress2]) - const newActiveAssets = Set([mockedActiveTokenAddress1]) - const oldSafe = getMockedOldSafe({ assets: oldActiveAssets }) - const newSafeProps: Partial = { - assets: newActiveAssets, - } - - // 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' diff --git a/src/logic/tokens/utils/__tests__/tokenHelpers.test.ts b/src/logic/tokens/utils/__tests__/tokenHelpers.test.ts index c211e8b4..142c2d6a 100644 --- a/src/logic/tokens/utils/__tests__/tokenHelpers.test.ts +++ b/src/logic/tokens/utils/__tests__/tokenHelpers.test.ts @@ -58,7 +58,7 @@ describe('getERC20DecimalsAndSymbol', () => { symbol, decimals, logoUri: 'https://gnosis-safe-token-logos.s3.amazonaws.com/0x5592EC0cfb4dbc12D3aB100b257153436a1f0FEa.png', - balance: 0, + balance: { tokenBalance: '0', fiatBalance: '0' }, }) const expectedResult = { decimals, From c41ab4eaec513752117c187d660b20db187a396b Mon Sep 17 00:00:00 2001 From: Fernando Date: Thu, 18 Mar 2021 14:02:48 -0300 Subject: [PATCH 04/15] (Chore) Update `nativeCoin` address to ZERO_ADDRESS (#2059) --- docs/networks.md | 4 +-- src/config/networks/energy_web_chain.ts | 2 +- src/config/networks/local.ts | 2 +- src/config/networks/mainnet.ts | 2 +- src/config/networks/rinkeby.ts | 2 +- src/config/networks/volta.ts | 2 +- src/config/networks/xdai.ts | 2 +- src/logic/safe/hooks/useTokenInfo.tsx | 8 ++---- src/logic/safe/utils/spendingLimits.ts | 26 +++---------------- .../tokens/store/actions/fetchSafeTokens.ts | 14 +++------- .../SpendingLimit/NewLimitModal/Review.tsx | 9 ++----- src/routes/safe/container/selector.ts | 4 +-- 12 files changed, 22 insertions(+), 55 deletions(-) diff --git a/docs/networks.md b/docs/networks.md index c048955a..4ec60e0c 100644 --- a/docs/networks.md +++ b/docs/networks.md @@ -286,7 +286,7 @@ const xDai: NetworkConfig = { label: 'xDai', isTestNet: false, nativeCoin: { - address: '0x000', + address: '0x0000000000000000000000000000000000000000', name: 'xDai', symbol: 'xDai', decimals: 18, @@ -343,7 +343,7 @@ const mainnet: NetworkConfig = { label: 'Mainnet', isTestNet: false, nativeCoin: { - address: '0x000', + address: '0x0000000000000000000000000000000000000000', name: 'Ether', symbol: 'ETH', decimals: 18, diff --git a/src/config/networks/energy_web_chain.ts b/src/config/networks/energy_web_chain.ts index 1f908757..7ba62198 100644 --- a/src/config/networks/energy_web_chain.ts +++ b/src/config/networks/energy_web_chain.ts @@ -38,7 +38,7 @@ const mainnet: NetworkConfig = { label: 'EWC', isTestNet: false, nativeCoin: { - address: '0x000', + address: '0x0000000000000000000000000000000000000000', name: 'Energy web token', symbol: 'EWT', decimals: 18, diff --git a/src/config/networks/local.ts b/src/config/networks/local.ts index a18d87bf..a2e9c8f8 100644 --- a/src/config/networks/local.ts +++ b/src/config/networks/local.ts @@ -29,7 +29,7 @@ const local: NetworkConfig = { label: 'LocalRPC', isTestNet: true, nativeCoin: { - address: '0x000', + address: '0x0000000000000000000000000000000000000000', name: 'Ether', symbol: 'ETH', decimals: 18, diff --git a/src/config/networks/mainnet.ts b/src/config/networks/mainnet.ts index cd330a8c..b4333c05 100644 --- a/src/config/networks/mainnet.ts +++ b/src/config/networks/mainnet.ts @@ -38,7 +38,7 @@ const mainnet: NetworkConfig = { label: 'Mainnet', isTestNet: false, nativeCoin: { - address: '0x000', + address: '0x0000000000000000000000000000000000000000', name: 'Ether', symbol: 'ETH', decimals: 18, diff --git a/src/config/networks/rinkeby.ts b/src/config/networks/rinkeby.ts index 0e035ecb..3ce8179f 100644 --- a/src/config/networks/rinkeby.ts +++ b/src/config/networks/rinkeby.ts @@ -38,7 +38,7 @@ const rinkeby: NetworkConfig = { label: 'Rinkeby', isTestNet: true, nativeCoin: { - address: '0x000', + address: '0x0000000000000000000000000000000000000000', name: 'Ether', symbol: 'ETH', decimals: 18, diff --git a/src/config/networks/volta.ts b/src/config/networks/volta.ts index e41c18cf..154ba9e8 100644 --- a/src/config/networks/volta.ts +++ b/src/config/networks/volta.ts @@ -35,7 +35,7 @@ const mainnet: NetworkConfig = { label: 'Volta', isTestNet: true, nativeCoin: { - address: '0x000', + address: '0x0000000000000000000000000000000000000000', name: 'Energy web token', symbol: 'EWT', decimals: 18, diff --git a/src/config/networks/xdai.ts b/src/config/networks/xdai.ts index e0763b78..3241806f 100644 --- a/src/config/networks/xdai.ts +++ b/src/config/networks/xdai.ts @@ -29,7 +29,7 @@ const xDai: NetworkConfig = { label: 'xDai', isTestNet: false, nativeCoin: { - address: '0x000', + address: '0x0000000000000000000000000000000000000000', name: 'xDai', symbol: 'xDai', decimals: 18, diff --git a/src/logic/safe/hooks/useTokenInfo.tsx b/src/logic/safe/hooks/useTokenInfo.tsx index c05f161c..0919611b 100644 --- a/src/logic/safe/hooks/useTokenInfo.tsx +++ b/src/logic/safe/hooks/useTokenInfo.tsx @@ -1,18 +1,14 @@ import { useSelector } from 'react-redux' -import { getNetworkInfo } from 'src/config' import { Token } from 'src/logic/tokens/store/model/token' -import { sameAddress, ZERO_ADDRESS } from 'src/logic/wallets/ethAddresses' +import { sameAddress } from 'src/logic/wallets/ethAddresses' import { safeKnownCoins } from 'src/routes/safe/container/selector' -const { nativeCoin } = getNetworkInfo() - const useTokenInfo = (address: string): Token | undefined => { const tokens = useSelector(safeKnownCoins) if (tokens) { - const tokenAddress = sameAddress(address, ZERO_ADDRESS) ? nativeCoin.address : address - return tokens.find((token) => sameAddress(token.address, tokenAddress)) ?? undefined + return tokens.find((token) => sameAddress(token.address, address)) } } diff --git a/src/logic/safe/utils/spendingLimits.ts b/src/logic/safe/utils/spendingLimits.ts index 1c20e890..cbf438a3 100644 --- a/src/logic/safe/utils/spendingLimits.ts +++ b/src/logic/safe/utils/spendingLimits.ts @@ -1,5 +1,4 @@ import { BigNumber } from 'bignumber.js' -import { getNetworkInfo } from 'src/config' import { AbiItem } from 'web3-utils' import { CreateTransactionArgs } from 'src/logic/safe/store/actions/createTransaction' @@ -9,7 +8,7 @@ import SpendingLimitModule from 'src/logic/contracts/artifacts/AllowanceModule.j import generateBatchRequests from 'src/logic/contracts/generateBatchRequests' import { getSpendingLimitContract, MULTI_SEND_ADDRESS } from 'src/logic/contracts/safeContracts' import { SpendingLimit } from 'src/logic/safe/store/models/safe' -import { sameAddress, ZERO_ADDRESS } from 'src/logic/wallets/ethAddresses' +import { sameAddress } from 'src/logic/wallets/ethAddresses' import { getWeb3, web3ReadOnly } from 'src/logic/wallets/getWeb3' import { SPENDING_LIMIT_MODULE_ADDRESS } from 'src/utils/constants' import { getEncodedMultiSendCallData, MultiSendTx } from './upgradeSafe' @@ -138,16 +137,13 @@ type DeleteAllowanceParams = { } export const getDeleteAllowanceTxData = ({ beneficiary, tokenAddress }: DeleteAllowanceParams): string => { - const { nativeCoin } = getNetworkInfo() - const token = sameAddress(tokenAddress, nativeCoin.address) ? ZERO_ADDRESS : tokenAddress - const web3 = getWeb3() const spendingLimitContract = new web3.eth.Contract( SpendingLimitModule.abi as AbiItem[], SPENDING_LIMIT_MODULE_ADDRESS, ) - return spendingLimitContract.methods.deleteAllowance(beneficiary, token).encodeABI() + return spendingLimitContract.methods.deleteAllowance(beneficiary, tokenAddress).encodeABI() } export const enableSpendingLimitModuleMultiSendTx = (safeAddress: string): MultiSendTx => { @@ -188,20 +184,13 @@ export const setSpendingLimitTx = ({ safeAddress, }: SpendingLimitTxParams): CreateTransactionArgs => { const spendingLimitContract = getSpendingLimitContract() - const { nativeCoin } = getNetworkInfo() const txArgs: CreateTransactionArgs = { safeAddress, to: SPENDING_LIMIT_MODULE_ADDRESS, valueInWei: ZERO_VALUE, txData: spendingLimitContract.methods - .setAllowance( - beneficiary, - token === nativeCoin.address ? ZERO_ADDRESS : token, - spendingLimitInWei, - resetTimeMin, - resetBaseMin, - ) + .setAllowance(beneficiary, token, spendingLimitInWei, resetTimeMin, resetBaseMin) .encodeABI(), operation: CALL, notifiedTransaction: TX_NOTIFICATION_TYPES.NEW_SPENDING_LIMIT_TX, @@ -285,12 +274,5 @@ export const getSpendingLimitByTokenAddress = ({ return } - const { nativeCoin } = getNetworkInfo() - - return spendingLimits.find(({ token: spendingLimitTokenAddress }) => { - spendingLimitTokenAddress = sameAddress(spendingLimitTokenAddress, ZERO_ADDRESS) - ? nativeCoin.address - : spendingLimitTokenAddress - return sameAddress(spendingLimitTokenAddress, tokenAddress) - }) + return spendingLimits.find(({ token }) => sameAddress(token, tokenAddress)) } diff --git a/src/logic/tokens/store/actions/fetchSafeTokens.ts b/src/logic/tokens/store/actions/fetchSafeTokens.ts index 227c49b8..d6414ade 100644 --- a/src/logic/tokens/store/actions/fetchSafeTokens.ts +++ b/src/logic/tokens/store/actions/fetchSafeTokens.ts @@ -11,8 +11,6 @@ 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 { sameAddress, ZERO_ADDRESS } from 'src/logic/wallets/ethAddresses' -import { getNetworkInfo } from 'src/config' import BigNumber from 'bignumber.js' import { currentCurrencySelector } from 'src/logic/currencyValues/store/selectors' @@ -27,24 +25,20 @@ interface ExtractedData { tokens: List } -const { nativeCoin } = getNetworkInfo() - const extractDataFromResult = (currentTokens: TokenState) => ( acc: ExtractedData, { balance, fiatBalance, tokenInfo }: TokenBalance, ): ExtractedData => { - const { address: tokenAddress, decimals } = tokenInfo - if (sameAddress(tokenAddress, ZERO_ADDRESS) || sameAddress(tokenAddress, nativeCoin.address)) { - acc.ethBalance = humanReadableValue(balance, 18) - } + const { address, decimals } = tokenInfo + acc.balances = acc.balances.merge({ - [tokenAddress]: { + [address]: { fiatBalance, tokenBalance: humanReadableValue(balance, Number(decimals)), }, }) - if (currentTokens && !currentTokens.get(tokenAddress)) { + if (currentTokens && !currentTokens.get(address)) { acc.tokens = acc.tokens.push(makeToken({ ...tokenInfo })) } diff --git a/src/routes/safe/components/Settings/SpendingLimit/NewLimitModal/Review.tsx b/src/routes/safe/components/Settings/SpendingLimit/NewLimitModal/Review.tsx index 0eced1a2..9ef63bd4 100644 --- a/src/routes/safe/components/Settings/SpendingLimit/NewLimitModal/Review.tsx +++ b/src/routes/safe/components/Settings/SpendingLimit/NewLimitModal/Review.tsx @@ -5,7 +5,6 @@ import { useDispatch, useSelector } from 'react-redux' import Block from 'src/components/layout/Block' import Col from 'src/components/layout/Col' import Row from 'src/components/layout/Row' -import { getNetworkInfo } from 'src/config' import { createTransaction, CreateTransactionArgs } from 'src/logic/safe/store/actions/createTransaction' import { SafeRecordProps, SpendingLimit } from 'src/logic/safe/store/models/safe' import { @@ -20,7 +19,7 @@ import { import { MultiSendTx } from 'src/logic/safe/utils/upgradeSafe' import { makeToken, Token } from 'src/logic/tokens/store/model/token' import { fromTokenUnit, toTokenUnit } from 'src/logic/tokens/utils/humanReadableValue' -import { sameAddress, ZERO_ADDRESS } from 'src/logic/wallets/ethAddresses' +import { sameAddress } from 'src/logic/wallets/ethAddresses' import { RESET_TIME_OPTIONS } from 'src/routes/safe/components/Settings/SpendingLimit/FormFields/ResetTime' import { AddressInfo, ResetTimeInfo, TokenInfo } from 'src/routes/safe/components/Settings/SpendingLimit/InfoDisplay' import Modal from 'src/routes/safe/components/Settings/SpendingLimit/Modal' @@ -34,8 +33,6 @@ import { EditableTxParameters } from 'src/routes/safe/components/Transactions/he import { TransactionFees } from 'src/components/TransactionsFees' import { EstimationStatus, useEstimateTransactionGas } from 'src/logic/hooks/useEstimateTransactionGas' -const { nativeCoin } = getNetworkInfo() - const useExistentSpendingLimit = ({ spendingLimits, txToken, @@ -51,9 +48,7 @@ const useExistentSpendingLimit = ({ return useMemo(() => { // if `delegate` already exist, check what tokens were delegated to the _beneficiary_ `getTokens(safe, delegate)` const currentDelegate = spendingLimits?.find( - ({ delegate, token }) => - sameAddress(delegate, values.beneficiary) && - sameAddress(token, sameAddress(values.token, nativeCoin.address) ? ZERO_ADDRESS : values.token), + ({ delegate, token }) => sameAddress(delegate, values.beneficiary) && sameAddress(token, values.token), ) // let the user know that is about to replace an existent allowance diff --git a/src/routes/safe/container/selector.ts b/src/routes/safe/container/selector.ts index 11420339..6899dd78 100644 --- a/src/routes/safe/container/selector.ts +++ b/src/routes/safe/container/selector.ts @@ -4,7 +4,7 @@ import { createSelector } from 'reselect' import { Token } from 'src/logic/tokens/store/model/token' import { tokensSelector } from 'src/logic/tokens/store/selectors' import { getEthAsToken } from 'src/logic/tokens/utils/tokenHelpers' -import { isUserAnOwner, sameAddress, ZERO_ADDRESS } from 'src/logic/wallets/ethAddresses' +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' @@ -37,7 +37,7 @@ export const extendedSafeTokensSelector = createSelector( if (baseToken) { const updatedBaseToken = baseToken.set('balance', tokenBalance || { tokenBalance: '0', fiatBalance: '0' }) - if (sameAddress(tokenAddress, ZERO_ADDRESS) || sameAddress(tokenAddress, ethAsToken?.address)) { + if (sameAddress(tokenAddress, ethAsToken?.address)) { map.set(tokenAddress, updatedBaseToken.set('logoUri', ethAsToken?.logoUri || baseToken.logoUri)) } else { map.set(tokenAddress, updatedBaseToken) From 253137d2ba26bf68338287be184d2491820958a9 Mon Sep 17 00:00:00 2001 From: Mikhail Mikheev Date: Mon, 22 Mar 2021 20:59:12 +0300 Subject: [PATCH 05/15] Bug: Safe app communicator is not properly initialized sometimes, thus app fails to communicate (#2069) * use iframeRef inside app communicator --- src/routes/safe/components/Apps/communicator.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/routes/safe/components/Apps/communicator.ts b/src/routes/safe/components/Apps/communicator.ts index 8422d3d7..00155bec 100644 --- a/src/routes/safe/components/Apps/communicator.ts +++ b/src/routes/safe/components/Apps/communicator.ts @@ -15,12 +15,12 @@ type MessageHandler = ( ) => void | MethodToResponse[Methods] | ErrorResponse | Promise class AppCommunicator { - private iframe: HTMLIFrameElement + private iframeRef: MutableRefObject private handlers = new Map() private app: SafeApp - constructor(iframeRef: MutableRefObject, app: SafeApp) { - this.iframe = iframeRef.current + constructor(iframeRef: MutableRefObject, app: SafeApp) { + this.iframeRef = iframeRef this.app = app window.addEventListener('message', this.handleIncomingMessage) @@ -49,7 +49,7 @@ class AppCommunicator { ? MessageFormatter.makeErrorResponse(requestId, data, sdkVersion) : MessageFormatter.makeResponse(requestId, data, sdkVersion) - this.iframe.contentWindow?.postMessage(msg, this.app.url) + this.iframeRef.current?.contentWindow?.postMessage(msg, this.app.url) } handleIncomingMessage = async (msg: SDKMessageEvent): Promise => { @@ -83,7 +83,6 @@ const useAppCommunicator = ( app?: SafeApp, ): AppCommunicator | undefined => { const [communicator, setCommunicator] = useState(undefined) - useEffect(() => { let communicatorInstance const initCommunicator = (iframeRef: MutableRefObject, app: SafeApp) => { @@ -91,7 +90,7 @@ const useAppCommunicator = ( setCommunicator(communicatorInstance) } - if (app && iframeRef.current !== null) { + if (app) { initCommunicator(iframeRef as MutableRefObject, app) } From da9031568f12d014c2d8fcb0af9c2eea18687300 Mon Sep 17 00:00:00 2001 From: nicolas Date: Tue, 23 Mar 2021 05:01:49 -0300 Subject: [PATCH 06/15] Advanced Options refactor (#2029) * useEstimateTxGas: set the correct value of isOffChainSignature if gas estimation fails --- src/logic/hooks/useEstimateTransactionGas.tsx | 5 +- .../components/ConfirmTransactionModal.tsx | 12 +-- .../ContractInteraction/Review/index.tsx | 3 + .../ReviewCustomTx/index.tsx | 9 +- .../screens/ReviewCollectible/index.tsx | 3 + .../screens/ReviewSendFundsTx/index.tsx | 7 +- .../Settings/Advanced/RemoveModuleModal.tsx | 3 + .../AddOwnerModal/screens/Review/index.tsx | 3 + .../RemoveOwnerModal/screens/Review/index.tsx | 3 + .../screens/Review/index.tsx | 3 + .../SpendingLimit/NewLimitModal/Review.tsx | 3 + .../SpendingLimit/RemoveLimitModal.tsx | 3 + .../ChangeThreshold/index.tsx | 6 +- .../Settings/UpdateSafeModal/index.tsx | 9 +- .../TxList/modals/ApproveTxModal.tsx | 5 +- .../TxList/modals/RejectTxModal.tsx | 3 + .../helpers/EditTxParametersForm/index.tsx | 96 ++++++++++--------- .../helpers/EditableTxParameters.tsx | 7 +- .../helpers/TxParametersDetail/index.tsx | 81 ++++++---------- .../components/Transactions/helpers/utils.ts | 10 +- 20 files changed, 153 insertions(+), 121 deletions(-) diff --git a/src/logic/hooks/useEstimateTransactionGas.tsx b/src/logic/hooks/useEstimateTransactionGas.tsx index 8cd5e268..567d7659 100644 --- a/src/logic/hooks/useEstimateTransactionGas.tsx +++ b/src/logic/hooks/useEstimateTransactionGas.tsx @@ -218,10 +218,9 @@ export const useEstimateTransactionGas = ({ ) const fixedGasCosts = getFixedGasCosts(Number(threshold)) + const isOffChainSignature = checkIfOffChainSignatureIsPossible(isExecution, smartContractWallet, safeVersion) try { - const isOffChainSignature = checkIfOffChainSignatureIsPossible(isExecution, smartContractWallet, safeVersion) - const gasEstimation = await estimateTransactionGas({ safeAddress, txRecipient, @@ -279,7 +278,7 @@ export const useEstimateTransactionGas = ({ gasLimit: '0', isExecution, isCreation, - isOffChainSignature: false, + isOffChainSignature, }) } } diff --git a/src/routes/safe/components/Apps/components/ConfirmTransactionModal.tsx b/src/routes/safe/components/Apps/components/ConfirmTransactionModal.tsx index 784c9e33..4815717f 100644 --- a/src/routes/safe/components/Apps/components/ConfirmTransactionModal.tsx +++ b/src/routes/safe/components/Apps/components/ConfirmTransactionModal.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useMemo, useState } from 'react' import { Icon, ModalFooterConfirmation, Text, Title } from '@gnosis.pm/safe-react-components' import { Transaction } from '@gnosis.pm/safe-apps-sdk-v1' import styled from 'styled-components' -import { useDispatch, useSelector } from 'react-redux' +import { useDispatch } from 'react-redux' import AddressInfo from 'src/components/AddressInfo' import DividerLine from 'src/components/DividerLine' @@ -26,7 +26,6 @@ import GasEstimationInfo from './GasEstimationInfo' import { getNetworkInfo } from 'src/config' import { TransactionParams } from './AppFrame' import { EstimationStatus, useEstimateTransactionGas } from 'src/logic/hooks/useEstimateTransactionGas' -import { safeThresholdSelector } from 'src/logic/safe/store/selectors' import Modal from 'src/components/Modal' import Row from 'src/components/layout/Row' import Hairline from 'src/components/layout/Hairline' @@ -123,7 +122,6 @@ export const ConfirmTransactionModal = ({ onTxReject, }: OwnProps): React.ReactElement | null => { const [estimatedSafeTxGas, setEstimatedSafeTxGas] = useState(0) - const threshold = useSelector(safeThresholdSelector) || 1 const txRecipient: string | undefined = useMemo(() => (txs.length > 1 ? MULTI_SEND_ADDRESS : txs[0]?.to), [txs]) const txData: string | undefined = useMemo(() => (txs.length > 1 ? encodeMultiSendCall(txs) : txs[0]?.data), [txs]) @@ -174,8 +172,6 @@ export const ConfirmTransactionModal = ({ onClose() } - const getParametersStatus = () => (threshold > 1 ? 'ETH_DISABLED' : 'ENABLED') - const confirmTransactions = async (txParameters: TxParameters) => { await dispatch( createTransaction( @@ -274,9 +270,9 @@ export const ConfirmTransactionModal = ({ {txEstimationExecutionStatus === EstimationStatus.LOADING ? null : ( @@ -297,16 +293,16 @@ export const ConfirmTransactionModal = ({ return ( {(txParameters, toggleEditMode) => ( <> - {body(txParameters, toggleEditMode)} diff --git a/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/Review/index.tsx b/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/Review/index.tsx index 5311f2e4..9352bcdb 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/Review/index.tsx +++ b/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/Review/index.tsx @@ -126,6 +126,8 @@ const ContractInteractionReview = ({ onClose, onPrev, tx }: Props): React.ReactE return (
diff --git a/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/ReviewCustomTx/index.tsx b/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/ReviewCustomTx/index.tsx index d7e4e736..0a39b8dc 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/ReviewCustomTx/index.tsx +++ b/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/ReviewCustomTx/index.tsx @@ -94,7 +94,13 @@ const ReviewCustomTx = ({ onClose, onPrev, tx }: Props): React.ReactElement => { } return ( - + {(txParameters, toggleEditMode) => ( <> @@ -168,6 +174,7 @@ const ReviewCustomTx = ({ onClose, onPrev, tx }: Props): React.ReactElement => { onEdit={toggleEditMode} isTransactionCreation={isCreation} isTransactionExecution={isExecution} + isOffChainSignature={isOffChainSignature} /> {txEstimationExecutionStatus === EstimationStatus.LOADING ? null : ( diff --git a/src/routes/safe/components/Balances/SendModal/screens/ReviewCollectible/index.tsx b/src/routes/safe/components/Balances/SendModal/screens/ReviewCollectible/index.tsx index f46d897c..ea68ea2a 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ReviewCollectible/index.tsx +++ b/src/routes/safe/components/Balances/SendModal/screens/ReviewCollectible/index.tsx @@ -140,6 +140,8 @@ const ReviewCollectible = ({ onClose, onPrev, tx }: Props): React.ReactElement = return (
diff --git a/src/routes/safe/components/Balances/SendModal/screens/ReviewSendFundsTx/index.tsx b/src/routes/safe/components/Balances/SendModal/screens/ReviewSendFundsTx/index.tsx index 21e0075c..1e2ab83c 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ReviewSendFundsTx/index.tsx +++ b/src/routes/safe/components/Balances/SendModal/screens/ReviewSendFundsTx/index.tsx @@ -178,6 +178,8 @@ const ReviewSendFundsTx = ({ onClose, onPrev, tx }: ReviewTxProps): React.ReactE return ( - - {/* Disclaimer */} + + {/* Disclaimer */} {txEstimationExecutionStatus !== EstimationStatus.LOADING && (
diff --git a/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/Review/index.tsx b/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/Review/index.tsx index dd53427a..1acbd6ef 100644 --- a/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/Review/index.tsx +++ b/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/Review/index.tsx @@ -101,6 +101,8 @@ export const ReviewAddOwner = ({ onClickBack, onClose, onSubmit, values }: Revie return ( diff --git a/src/routes/safe/components/Settings/ManageOwners/RemoveOwnerModal/screens/Review/index.tsx b/src/routes/safe/components/Settings/ManageOwners/RemoveOwnerModal/screens/Review/index.tsx index c69aba52..7d77084c 100644 --- a/src/routes/safe/components/Settings/ManageOwners/RemoveOwnerModal/screens/Review/index.tsx +++ b/src/routes/safe/components/Settings/ManageOwners/RemoveOwnerModal/screens/Review/index.tsx @@ -123,6 +123,8 @@ export const ReviewRemoveOwnerModal = ({ return ( {txEstimationExecutionStatus === EstimationStatus.LOADING ? null : ( diff --git a/src/routes/safe/components/Settings/ManageOwners/ReplaceOwnerModal/screens/Review/index.tsx b/src/routes/safe/components/Settings/ManageOwners/ReplaceOwnerModal/screens/Review/index.tsx index fa47290b..52327599 100644 --- a/src/routes/safe/components/Settings/ManageOwners/ReplaceOwnerModal/screens/Review/index.tsx +++ b/src/routes/safe/components/Settings/ManageOwners/ReplaceOwnerModal/screens/Review/index.tsx @@ -120,6 +120,8 @@ export const ReviewReplaceOwnerModal = ({ return ( diff --git a/src/routes/safe/components/Settings/SpendingLimit/NewLimitModal/Review.tsx b/src/routes/safe/components/Settings/SpendingLimit/NewLimitModal/Review.tsx index 9ef63bd4..9d803ded 100644 --- a/src/routes/safe/components/Settings/SpendingLimit/NewLimitModal/Review.tsx +++ b/src/routes/safe/components/Settings/SpendingLimit/NewLimitModal/Review.tsx @@ -233,6 +233,8 @@ export const ReviewSpendingLimits = ({ onBack, onClose, txToken, values }: Revie return (
diff --git a/src/routes/safe/components/Settings/SpendingLimit/RemoveLimitModal.tsx b/src/routes/safe/components/Settings/SpendingLimit/RemoveLimitModal.tsx index 0c5a5090..6ad0ec6e 100644 --- a/src/routes/safe/components/Settings/SpendingLimit/RemoveLimitModal.tsx +++ b/src/routes/safe/components/Settings/SpendingLimit/RemoveLimitModal.tsx @@ -116,6 +116,8 @@ export const RemoveLimitModal = ({ onClose, spendingLimit, open }: RemoveSpendin description="Remove the selected Spending Limit" > diff --git a/src/routes/safe/components/Settings/ThresholdSettings/ChangeThreshold/index.tsx b/src/routes/safe/components/Settings/ThresholdSettings/ChangeThreshold/index.tsx index 8f6a7455..0560b57a 100644 --- a/src/routes/safe/components/Settings/ThresholdSettings/ChangeThreshold/index.tsx +++ b/src/routes/safe/components/Settings/ThresholdSettings/ChangeThreshold/index.tsx @@ -84,8 +84,6 @@ export const ChangeThresholdModal = ({ } }, [safeAddress, editedThreshold]) - const getParametersStatus = () => (threshold > 1 ? 'ETH_DISABLED' : 'ENABLED') - const handleSubmit = async ({ txParameters }) => { await dispatch( createTransaction({ @@ -120,6 +118,8 @@ export const ChangeThresholdModal = ({ return ( {txEstimationExecutionStatus !== EstimationStatus.LOADING && ( diff --git a/src/routes/safe/components/Settings/UpdateSafeModal/index.tsx b/src/routes/safe/components/Settings/UpdateSafeModal/index.tsx index aea5f0ce..b56ae3d0 100644 --- a/src/routes/safe/components/Settings/UpdateSafeModal/index.tsx +++ b/src/routes/safe/components/Settings/UpdateSafeModal/index.tsx @@ -76,7 +76,13 @@ export const UpdateSafeModal = ({ onClose, safeAddress }: Props): React.ReactEle }) return ( - + {(txParameters, toggleEditMode) => ( <> @@ -116,6 +122,7 @@ export const UpdateSafeModal = ({ onClose, safeAddress }: Props): React.ReactEle compact={false} isTransactionCreation={isCreation} isTransactionExecution={isExecution} + isOffChainSignature={isOffChainSignature} /> {txEstimationExecutionStatus === EstimationStatus.LOADING ? null : ( diff --git a/src/routes/safe/components/Transactions/TxList/modals/ApproveTxModal.tsx b/src/routes/safe/components/Transactions/TxList/modals/ApproveTxModal.tsx index 687dea96..c8b24649 100644 --- a/src/routes/safe/components/Transactions/TxList/modals/ApproveTxModal.tsx +++ b/src/routes/safe/components/Transactions/TxList/modals/ApproveTxModal.tsx @@ -317,6 +317,8 @@ export const ApproveTxModal = ({ return ( )} diff --git a/src/routes/safe/components/Transactions/TxList/modals/RejectTxModal.tsx b/src/routes/safe/components/Transactions/TxList/modals/RejectTxModal.tsx index 48280b8e..8ebf6186 100644 --- a/src/routes/safe/components/Transactions/TxList/modals/RejectTxModal.tsx +++ b/src/routes/safe/components/Transactions/TxList/modals/RejectTxModal.tsx @@ -82,6 +82,8 @@ export const RejectTxModal = ({ isOpen, onClose, gwTransaction }: Props): React. return ( diff --git a/src/routes/safe/components/Transactions/helpers/EditTxParametersForm/index.tsx b/src/routes/safe/components/Transactions/helpers/EditTxParametersForm/index.tsx index 436df795..a497eb2b 100644 --- a/src/routes/safe/components/Transactions/helpers/EditTxParametersForm/index.tsx +++ b/src/routes/safe/components/Transactions/helpers/EditTxParametersForm/index.tsx @@ -15,11 +15,11 @@ import GnoForm from 'src/components/forms/GnoForm' import { TxParameters } from 'src/routes/safe/container/hooks/useTransactionParameters' import { composeValidators, minValue } from 'src/components/forms/validator' -import { ParametersStatus, areSafeParamsEnabled, areEthereumParamsEnabled } from '../utils' +import { ParametersStatus, areSafeParamsEnabled, areEthereumParamsVisible, ethereumTxParametersTitle } from '../utils' import { getNetworkInfo } from 'src/config' const StyledDivider = styled(Divider)` - margin: 0px; + margin: 16px 0; ` const SafeOptions = styled.div` @@ -39,7 +39,7 @@ const EthereumOptions = styled.div` } ` const StyledLink = styled(Link)` - margin: 16px 0; + margin: 16px 0 0 0; display: inline-flex; align-items: center; @@ -65,6 +65,7 @@ interface Props { txParameters: TxParameters onClose: (txParameters?: TxParameters) => void parametersStatus: ParametersStatus + isExecution: boolean } const formValidation = (values) => { @@ -101,6 +102,7 @@ export const EditTxParametersForm = ({ onClose, txParameters, parametersStatus = 'ENABLED', + isExecution, }: Props): React.ReactElement => { const classes = useStyles() const { safeNonce, safeTxGas, ethNonce, ethGasLimit, ethGasPrice } = txParameters @@ -142,7 +144,7 @@ export const EditTxParametersForm = ({ {() => ( <> - Safe transactions parameters + Safe transaction @@ -168,49 +170,53 @@ export const EditTxParametersForm = ({ /> - - Ethereum transactions parameters - + {areEthereumParamsVisible(parametersStatus) && ( + <> + + {ethereumTxParametersTitle(isExecution)} + - - - - - + + + + + - - - How can I configure the gas price manually? - - - + + + How can I configure these parameters manually? + + + + + )} diff --git a/src/routes/safe/components/Transactions/helpers/EditableTxParameters.tsx b/src/routes/safe/components/Transactions/helpers/EditableTxParameters.tsx index a4a29ada..fb9eac57 100644 --- a/src/routes/safe/components/Transactions/helpers/EditableTxParameters.tsx +++ b/src/routes/safe/components/Transactions/helpers/EditableTxParameters.tsx @@ -7,6 +7,8 @@ import { safeThresholdSelector } from 'src/logic/safe/store/selectors' type Props = { children: (txParameters: TxParameters, toggleStatus: (txParameters?: TxParameters) => void) => any + isOffChainSignature: boolean + isExecution: boolean parametersStatus?: ParametersStatus ethGasLimit?: TxParameters['ethGasLimit'] ethGasPrice?: TxParameters['ethGasPrice'] @@ -17,6 +19,8 @@ type Props = { export const EditableTxParameters = ({ children, + isOffChainSignature, + isExecution, parametersStatus, ethGasLimit, ethGasPrice, @@ -27,7 +31,7 @@ export const EditableTxParameters = ({ const [isEditMode, toggleEditMode] = useState(false) const [useManualValues, setUseManualValues] = useState(false) const threshold = useSelector(safeThresholdSelector) || 1 - const defaultParameterStatus = threshold > 1 ? 'ETH_DISABLED' : 'ENABLED' + const defaultParameterStatus = isOffChainSignature && threshold > 1 ? 'ETH_HIDDEN' : 'ENABLED' const txParameters = useTransactionParameters({ parameterStatus: parametersStatus || defaultParameterStatus, initialEthGasLimit: ethGasLimit, @@ -65,6 +69,7 @@ export const EditableTxParameters = ({ return isEditMode ? ( void compact?: boolean parametersStatus?: ParametersStatus - isTransactionExecution: boolean isTransactionCreation: boolean + isTransactionExecution: boolean + isOffChainSignature: boolean } export const TxParametersDetail = ({ @@ -46,11 +47,12 @@ export const TxParametersDetail = ({ parametersStatus, isTransactionCreation, isTransactionExecution, + isOffChainSignature, }: Props): ReactElement | null => { const threshold = useSelector(safeThresholdSelector) || 1 - const defaultParameterStatus = threshold > 1 ? 'ETH_DISABLED' : 'ENABLED' + const defaultParameterStatus = isOffChainSignature && threshold > 1 ? 'ETH_HIDDEN' : 'ENABLED' - if (!isTransactionExecution && !isTransactionCreation) { + if (!isTransactionExecution && !isTransactionCreation && isOffChainSignature) { return null } @@ -62,7 +64,7 @@ export const TxParametersDetail = ({ - Safe transactions parameters + Safe transaction @@ -95,57 +97,30 @@ export const TxParametersDetail = ({ - - - Ethereum transaction parameters - - + {areEthereumParamsVisible(parametersStatus || defaultParameterStatus) && ( + <> + + + {ethereumTxParametersTitle(isTransactionExecution)} + + - - - Ethereum nonce - - - {txParameters.ethNonce} - - + + Nonce + {txParameters.ethNonce} + - - - Ethereum gas limit - - - {txParameters.ethGasLimit} - - - - - - Ethereum gas price - - - {txParameters.ethGasPrice} - - + + Gas limit + {txParameters.ethGasLimit} + + + Gas price + {txParameters.ethGasPrice} + + + )} Edit diff --git a/src/routes/safe/components/Transactions/helpers/utils.ts b/src/routes/safe/components/Transactions/helpers/utils.ts index ce1564e6..ccb3742f 100644 --- a/src/routes/safe/components/Transactions/helpers/utils.ts +++ b/src/routes/safe/components/Transactions/helpers/utils.ts @@ -1,8 +1,8 @@ -export type ParametersStatus = 'ENABLED' | 'DISABLED' | 'SAFE_DISABLED' | 'ETH_DISABLED' | 'CANCEL_TRANSACTION' +export type ParametersStatus = 'ENABLED' | 'DISABLED' | 'SAFE_DISABLED' | 'ETH_HIDDEN' | 'CANCEL_TRANSACTION' -export const areEthereumParamsEnabled = (parametersStatus: ParametersStatus): boolean => { +export const areEthereumParamsVisible = (parametersStatus: ParametersStatus): boolean => { return ( - parametersStatus === 'ENABLED' || (parametersStatus !== 'ETH_DISABLED' && parametersStatus !== 'CANCEL_TRANSACTION') + parametersStatus === 'ENABLED' || (parametersStatus !== 'ETH_HIDDEN' && parametersStatus !== 'CANCEL_TRANSACTION') ) } @@ -12,3 +12,7 @@ export const areSafeParamsEnabled = (parametersStatus: ParametersStatus): boolea (parametersStatus !== 'SAFE_DISABLED' && parametersStatus !== 'CANCEL_TRANSACTION') ) } + +export const ethereumTxParametersTitle = (isExecution: boolean): string => { + return `Owner transaction ${isExecution ? '(Execution)' : '(On-chain approval)'}` +} From 4297671869f931f759500c3f1fa10c198d514910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agust=C3=ADn=20Longoni?= Date: Tue, 23 Mar 2021 05:48:49 -0300 Subject: [PATCH 07/15] (Fix) change error message Contract address input (#2060) * change error message Contract address input --- src/components/forms/validator.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/forms/validator.ts b/src/components/forms/validator.ts index 271c27ba..09496afa 100644 --- a/src/components/forms/validator.ts +++ b/src/components/forms/validator.ts @@ -80,9 +80,7 @@ export const mustBeEthereumContractAddress = memoize( async (address: string): Promise => { const contractCode = await getWeb3().eth.getCode(address) - const errorMessage = `Input must be a valid Ethereum contract address${ - isFeatureEnabled(FEATURES.DOMAIN_LOOKUP) ? ', ENS or Unstoppable domain' : '' - }` + const errorMessage = `Must resolve to a valid smart contract address.` return !contractCode || contractCode.replace('0x', '').replace(/0/g, '') === '' ? errorMessage : undefined }, From 6bf81df271e94378211ac1eb8abfc48d82e0668f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Mart=C3=ADnez?= Date: Tue, 23 Mar 2021 13:15:49 +0100 Subject: [PATCH 08/15] Replace Safe logo in the header (#2070) * Set bigger logo size Co-authored-by: Daniel Sanchez --- .../Header/assets/gnosis-safe-multisig-logo.svg | 9 ++++----- src/components/AppLayout/Header/components/Layout.tsx | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/components/AppLayout/Header/assets/gnosis-safe-multisig-logo.svg b/src/components/AppLayout/Header/assets/gnosis-safe-multisig-logo.svg index 26f71351..62ed0fd9 100644 --- a/src/components/AppLayout/Header/assets/gnosis-safe-multisig-logo.svg +++ b/src/components/AppLayout/Header/assets/gnosis-safe-multisig-logo.svg @@ -1,6 +1,5 @@ - - - - - + + horizontal_left_small_black + + diff --git a/src/components/AppLayout/Header/components/Layout.tsx b/src/components/AppLayout/Header/components/Layout.tsx index 5845013f..85051334 100644 --- a/src/components/AppLayout/Header/components/Layout.tsx +++ b/src/components/AppLayout/Header/components/Layout.tsx @@ -38,7 +38,7 @@ const styles = () => ({ zIndex: 1301, }, logo: { - flexBasis: '114px', + flexBasis: '140px', flexShrink: '0', flexGrow: '0', maxWidth: '55px', From ab7643a51192d67e3de4b0b31a44365d8cc8791b Mon Sep 17 00:00:00 2001 From: Daniel Sanchez Date: Tue, 23 Mar 2021 14:15:14 +0100 Subject: [PATCH 09/15] Upgrade walletconnect to latest version --- src/routes/safe/components/Apps/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/safe/components/Apps/utils.ts b/src/routes/safe/components/Apps/utils.ts index 6d8a8c7d..31ae589f 100644 --- a/src/routes/safe/components/Apps/utils.ts +++ b/src/routes/safe/components/Apps/utils.ts @@ -131,7 +131,7 @@ export const staticAppsList: Array = [ }, // Wallet-Connect { - url: `${process.env.REACT_APP_IPFS_GATEWAY}/QmRMGTA5ARMwfhYbdmK83zzMd13NnEUKFJSZEgEjKa8YQm`, + url: `${process.env.REACT_APP_IPFS_GATEWAY}/QmU1pT35yPXxpnABcH3pZ1MxFeyYVtftT5RKhWopQmZHQV`, disabled: false, networks: [ ETHEREUM_NETWORK.MAINNET, From 63d88865e52ba86af29d5415fbba7a488e8e992b Mon Sep 17 00:00:00 2001 From: Mati Dastugue Date: Wed, 24 Mar 2021 05:44:20 -0300 Subject: [PATCH 10/15] Bugfix - Back button in modal resets form (#2075) * Use initialValues on SendFunds modal Co-authored-by: Daniel Sanchez --- .../safe/components/Balances/SendModal/index.tsx | 1 + .../Balances/SendModal/screens/SendFunds/index.tsx | 14 +++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/routes/safe/components/Balances/SendModal/index.tsx b/src/routes/safe/components/Balances/SendModal/index.tsx index 68a4e5ea..7623d9fa 100644 --- a/src/routes/safe/components/Balances/SendModal/index.tsx +++ b/src/routes/safe/components/Balances/SendModal/index.tsx @@ -133,6 +133,7 @@ const SendModal = ({ {activeScreen === 'sendFunds' && ( void onReview: (txInfo: unknown) => void recipientAddress?: string @@ -80,6 +81,7 @@ const InputAdornmentChildSymbol = ({ symbol }: { symbol?: string }): ReactElemen } const SendFunds = ({ + initialValues, onClose, onReview, recipientAddress, @@ -93,12 +95,14 @@ const SendFunds = ({ const defaultEntry = { address: recipientAddress || '', name: '' } // if there's nothing to lookup for, we return the default entry - if (!recipientAddress) { + if (!initialValues?.recipientAddress && !recipientAddress) { return defaultEntry } + // if there's something to lookup for, `initialValues` has precedence over `recipientAddress` + const predefinedAddress = initialValues?.recipientAddress ?? recipientAddress const addressBookEntry = addressBook.find(({ address }) => { - return sameAddress(recipientAddress, address) + return sameAddress(predefinedAddress, address) }) // if found in the Address Book, then we return the entry @@ -170,7 +174,11 @@ const SendFunds = ({ From 48b38f550a669c9e380d66089d82f392d71d80a1 Mon Sep 17 00:00:00 2001 From: nicolas Date: Wed, 24 Mar 2021 05:58:28 -0300 Subject: [PATCH 11/15] Add tx-decoding to safe-apps review modal. (#2061) * Modal refactor and txs decoded * Add Stepped modal and split Decoded tx components * fix bytes param and add word-break to modal Co-authored-by: Daniel Sanchez --- package.json | 2 +- src/components/DecodeTxs/index.tsx | 200 +++++++++++ src/components/ModalTitle/index.tsx | 25 +- .../components/Apps/components/AppFrame.tsx | 4 +- .../components/ConfirmTransactionModal.tsx | 324 ------------------ .../ConfirmTxModal/DecodedTxDetail.tsx | 62 ++++ .../ConfirmTxModal/ReviewConfirm.tsx | 260 ++++++++++++++ .../ConfirmTxModal/SafeAppLoadError.tsx | 47 +++ .../Apps/components/ConfirmTxModal/index.tsx | 72 ++++ src/types/transactions/decode.d.ts | 24 ++ src/utils/decodeTx.ts | 18 + yarn.lock | 4 +- 12 files changed, 706 insertions(+), 336 deletions(-) create mode 100644 src/components/DecodeTxs/index.tsx delete mode 100644 src/routes/safe/components/Apps/components/ConfirmTransactionModal.tsx create mode 100644 src/routes/safe/components/Apps/components/ConfirmTxModal/DecodedTxDetail.tsx create mode 100644 src/routes/safe/components/Apps/components/ConfirmTxModal/ReviewConfirm.tsx create mode 100644 src/routes/safe/components/Apps/components/ConfirmTxModal/SafeAppLoadError.tsx create mode 100644 src/routes/safe/components/Apps/components/ConfirmTxModal/index.tsx create mode 100644 src/types/transactions/decode.d.ts create mode 100644 src/utils/decodeTx.ts diff --git a/package.json b/package.json index 825b8173..bddbfe6c 100644 --- a/package.json +++ b/package.json @@ -161,7 +161,7 @@ "@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#f610327", + "@gnosis.pm/safe-react-components": "https://github.com/gnosis/safe-react-components.git#80f5db6", "@gnosis.pm/util-contracts": "2.0.6", "@ledgerhq/hw-transport-node-hid-singleton": "5.45.0", "@material-ui/core": "^4.11.0", diff --git a/src/components/DecodeTxs/index.tsx b/src/components/DecodeTxs/index.tsx new file mode 100644 index 00000000..2b49ed61 --- /dev/null +++ b/src/components/DecodeTxs/index.tsx @@ -0,0 +1,200 @@ +import React, { ReactElement } from 'react' +import styled from 'styled-components' +import { Transaction } from '@gnosis.pm/safe-apps-sdk-v1' +import { Text, EthHashInfo, CopyToClipboardBtn, IconText, FixedIcon } from '@gnosis.pm/safe-react-components' +import get from 'lodash.get' + +import { web3ReadOnly as web3 } from 'src/logic/wallets/getWeb3' +import { getExplorerInfo } from 'src/config' +import { DecodedData, DecodedDataBasicParameter, DecodedDataParameterValue } from 'src/types/transactions/decode.d' +import { DecodedTxDetail } from 'src/routes/safe/components/Apps/components/ConfirmTxModal' + +const FlexWrapper = styled.div<{ margin: number }>` + display: flex; + align-items: center; + + > :nth-child(2) { + margin-left: ${({ margin }) => margin}px; + } +` + +const BasicTxInfoWrapper = styled.div` + margin-bottom: 15px; + + > :nth-child(2) { + margin-bottom: 15px; + } +` + +const TxList = styled.div` + width: 100%; + max-height: 260px; + overflow-y: auto; + border-top: 2px solid ${({ theme }) => theme.colors.separator}; +` + +const TxListItem = styled.div` + display: flex; + justify-content: space-between; + + padding: 0 24px; + height: 50px; + border-bottom: 2px solid ${({ theme }) => theme.colors.separator}; + + :hover { + cursor: pointer; + } +` +const ElementWrapper = styled.div` + margin-bottom: 15px; +` + +export const BasicTxInfo = ({ + txRecipient, + txData, + txValue, +}: { + txRecipient: string + txData: string + txValue: string +}): ReactElement => { + return ( + + {/* TO */} + <> + + {`Send ${txValue} ETH to:`} + + + + <> + {/* Data */} + + Data (hex encoded): + + + {web3.utils.hexToBytes(txData).length} bytes + + + + + ) +} + +export const getParameterElement = (parameter: DecodedDataBasicParameter, index: number): ReactElement => { + let valueElement + + if (parameter.type === 'address') { + valueElement = ( + + ) + } + + if (parameter.type.startsWith('bytes')) { + valueElement = ( + + {web3.utils.hexToBytes(parameter.value).length} bytes + + + ) + } + + if (!valueElement) { + let value = parameter.value + if (parameter.type.endsWith('[]')) { + try { + value = JSON.stringify(parameter.value) + } catch (e) {} + } + valueElement = {value} + } + + return ( + + + {parameter.name} ({parameter.type}) + + {valueElement} + + ) +} + +const SingleTx = ({ + decodedData, + onTxItemClick, +}: { + decodedData: DecodedData | null + onTxItemClick: (decodedTxDetails: DecodedData) => void +}): ReactElement | null => { + if (!decodedData) { + return null + } + + return ( + + onTxItemClick(decodedData)}> + + + + {decodedData.method} + + + + + ) +} + +const MultiSendTx = ({ + decodedData, + onTxItemClick, +}: { + decodedData: DecodedData | null + onTxItemClick: (decodedTxDetails: DecodedDataParameterValue) => void +}): ReactElement | null => { + const txs: DecodedDataParameterValue[] | undefined = get(decodedData, 'parameters[0].valueDecoded') + + if (!txs) { + return null + } + + return ( + + {txs.map((tx, index) => ( + onTxItemClick(tx)}> + + + + {tx.dataDecoded && {tx.dataDecoded.method}} + + + + ))} + + ) +} + +type Props = { + txs: Transaction[] + decodedData: DecodedData | null + onTxItemClick: (decodedTxDetails: DecodedTxDetail) => void +} + +export const DecodeTxs = ({ txs, decodedData, onTxItemClick }: Props): ReactElement => { + return txs.length > 1 ? ( + + ) : ( + + ) +} diff --git a/src/components/ModalTitle/index.tsx b/src/components/ModalTitle/index.tsx index f2af9051..4b2a7f64 100644 --- a/src/components/ModalTitle/index.tsx +++ b/src/components/ModalTitle/index.tsx @@ -2,6 +2,7 @@ import React from 'react' import styled from 'styled-components' import IconButton from '@material-ui/core/IconButton' import Close from '@material-ui/icons/Close' +import { Icon } from '@gnosis.pm/safe-react-components' import Paragraph from 'src/components/layout/Paragraph' import { md, lg } from 'src/theme/variables' @@ -33,18 +34,28 @@ const StyledClose = styled(Close)` width: 35px; ` -const ModalTitle = ({ - iconUrl, - title, - onClose, -}: { +const GoBackWrapper = styled.div` + margin-right: 15px; +` + +type Props = { title: string - iconUrl: string + goBack?: () => void + iconUrl?: string onClose?: () => void -}): React.ReactElement => { +} + +const ModalTitle = ({ goBack, iconUrl, title, onClose }: Props): React.ReactElement => { return ( + {goBack && ( + + + + + + )} {iconUrl && } {title} diff --git a/src/routes/safe/components/Apps/components/AppFrame.tsx b/src/routes/safe/components/Apps/components/AppFrame.tsx index aebff2ab..62097c63 100644 --- a/src/routes/safe/components/Apps/components/AppFrame.tsx +++ b/src/routes/safe/components/Apps/components/AppFrame.tsx @@ -32,7 +32,7 @@ import { LoadingContainer } from 'src/components/LoaderContainer/index' import { TIMEOUT } from 'src/utils/constants' import { web3ReadOnly } from 'src/logic/wallets/getWeb3' -import { ConfirmTransactionModal } from '../components/ConfirmTransactionModal' +import { ConfirmTxModal } from '../components/ConfirmTxModal' import { useIframeMessageHandler } from '../hooks/useIframeMessageHandler' import { useLegalConsent } from '../hooks/useLegalConsent' import LegalDisclaimer from './LegalDisclaimer' @@ -354,7 +354,7 @@ const AppFrame = ({ appUrl }: Props): React.ReactElement => { /> )} - { - if (!['string', 'number'].includes(typeof t.value)) { - return false - } - - if (typeof t.value === 'string' && !/^(0x)?[0-9a-f]+$/i.test(t.value)) { - return false - } - - const isAddressValid = mustBeEthereumAddress(t.to) === undefined - return isAddressValid && !!t.data && typeof t.data === 'string' -} - -const Wrapper = styled.div` - margin-bottom: 15px; -` -const CollapseContent = styled.div` - padding: 15px 0; - - .section { - margin-bottom: 15px; - } - - .value-section { - display: flex; - align-items: center; - } -` - -const IconText = styled.div` - display: flex; - align-items: center; - - span { - margin-right: 4px; - } -` -const StyledTextBox = styled(TextBox)` - max-width: 444px; -` - -const Container = styled.div` - max-width: 480px; - padding: ${md} ${lg}; -` - -const ModalFooter = styled(Row)` - padding: ${md} ${lg}; - justify-content: center; -` -const TransactionFeesWrapper = styled.div` - background-color: ${({ theme }) => theme.colors.background}; - padding: ${sm} ${lg}; -` - -type OwnProps = { - isOpen: boolean - app: SafeApp - txs: Transaction[] - params?: TransactionParams - safeAddress: string - safeName: string - ethBalance: string - onUserConfirm: (safeTxHash: string) => void - onTxReject: () => void - onClose: () => void -} - -const { nativeCoin } = getNetworkInfo() - -const parseTxValue = (value: string | number): string => { - return web3ReadOnly.utils.toBN(value).toString() -} - -export const ConfirmTransactionModal = ({ - isOpen, - app, - txs, - safeAddress, - ethBalance, - safeName, - params, - onUserConfirm, - onClose, - onTxReject, -}: OwnProps): React.ReactElement | null => { - const [estimatedSafeTxGas, setEstimatedSafeTxGas] = useState(0) - - const txRecipient: string | undefined = useMemo(() => (txs.length > 1 ? MULTI_SEND_ADDRESS : txs[0]?.to), [txs]) - const txData: string | undefined = useMemo(() => (txs.length > 1 ? encodeMultiSendCall(txs) : txs[0]?.data), [txs]) - const txValue: string | undefined = useMemo( - () => (txs.length > 1 ? '0' : txs[0]?.value && parseTxValue(txs[0]?.value)), - [txs], - ) - const operation = useMemo(() => (txs.length > 1 ? DELEGATE_CALL : CALL), [txs]) - const [manualSafeTxGas, setManualSafeTxGas] = useState(0) - const [manualGasPrice, setManualGasPrice] = useState() - - const { - gasLimit, - gasPriceFormatted, - gasEstimation, - isOffChainSignature, - isCreation, - isExecution, - gasCostFormatted, - txEstimationExecutionStatus, - } = useEstimateTransactionGas({ - txData: txData || '', - txRecipient, - operation, - txAmount: txValue, - safeTxGas: manualSafeTxGas, - manualGasPrice, - }) - - useEffect(() => { - if (params?.safeTxGas) { - setEstimatedSafeTxGas(gasEstimation) - } - }, [params, gasEstimation]) - - const dispatch = useDispatch() - if (!isOpen) { - return null - } - - const handleTxRejection = () => { - onTxReject() - onClose() - } - - const handleUserConfirmation = (safeTxHash: string): void => { - onUserConfirm(safeTxHash) - onClose() - } - - const confirmTransactions = async (txParameters: TxParameters) => { - await dispatch( - createTransaction( - { - safeAddress, - to: txRecipient, - valueInWei: txValue, - txData, - operation, - origin: app.id, - navigateToTransactionsTab: false, - txNonce: txParameters.safeNonce, - safeTxGas: txParameters.safeTxGas - ? Number(txParameters.safeTxGas) - : Math.max(params?.safeTxGas || 0, estimatedSafeTxGas), - ethParameters: txParameters, - notifiedTransaction: TX_NOTIFICATION_TYPES.STANDARD_TX, - }, - handleUserConfirmation, - handleTxRejection, - ), - ) - } - - const closeEditModalCallback = (txParameters: TxParameters) => { - const oldGasPrice = Number(gasPriceFormatted) - const newGasPrice = Number(txParameters.ethGasPrice) - const oldSafeTxGas = Number(gasEstimation) - const newSafeTxGas = Number(txParameters.safeTxGas) - - if (newGasPrice && oldGasPrice !== newGasPrice) { - setManualGasPrice(txParameters.ethGasPrice) - } - - if (newSafeTxGas && oldSafeTxGas !== newSafeTxGas) { - setManualSafeTxGas(newSafeTxGas) - } - } - - const areTxsMalformed = txs.some((t) => !isTxValid(t)) - - const body = areTxsMalformed - ? () => ( - <> - - - Transaction error - - - This Safe App initiated a transaction which cannot be processed. Please get in touch with the developer of - this Safe App for more information. - - - ) - : (txParameters, toggleEditMode) => { - return ( - <> - - - - {txs.map((tx, index) => ( - - } title={`Transaction ${index + 1}`}> - -
- Value -
- Ether - - {fromTokenUnit(tx.value, nativeCoin.decimals)} {nativeCoin.name} - -
-
-
- Data (hex encoded)* - {tx.data} -
- - - - ))} - - {params?.safeTxGas && ( -
- SafeTxGas - {params?.safeTxGas} - -
- )} - - {/* Tx Parameters */} - - - {txEstimationExecutionStatus === EstimationStatus.LOADING ? null : ( - - - - )} - - ) - } - - return ( - - - {(txParameters, toggleEditMode) => ( - <> - - - - {body(txParameters, toggleEditMode)} - - - confirmTransactions(txParameters)} - okDisabled={areTxsMalformed} - okText="Submit" - /> - - - )} - - - ) -} diff --git a/src/routes/safe/components/Apps/components/ConfirmTxModal/DecodedTxDetail.tsx b/src/routes/safe/components/Apps/components/ConfirmTxModal/DecodedTxDetail.tsx new file mode 100644 index 00000000..8bf9bb6a --- /dev/null +++ b/src/routes/safe/components/Apps/components/ConfirmTxModal/DecodedTxDetail.tsx @@ -0,0 +1,62 @@ +import React, { ReactElement } from 'react' +import styled from 'styled-components' + +import { getNetworkInfo } from 'src/config' +import { fromTokenUnit } from 'src/logic/tokens/utils/humanReadableValue' +import { md, lg } from 'src/theme/variables' +import ModalTitle from 'src/components/ModalTitle' +import Hairline from 'src/components/layout/Hairline' +import { DecodedDataParameterValue, DecodedData } from 'src/types/transactions/decode.d' +import { BasicTxInfo, getParameterElement } from 'src/components/DecodeTxs' + +const { nativeCoin } = getNetworkInfo() + +const Container = styled.div` + max-width: 480px; + padding: ${md} ${lg}; + word-break: break-word; +` + +function isDataDecodedParameterValue(arg: any): arg is DecodedDataParameterValue { + return arg.operation !== undefined +} + +type Props = { + hideDecodedTxData: () => void + onClose: () => void + decodedTxData: DecodedDataParameterValue | DecodedData +} + +export const DecodedTxDetail = ({ hideDecodedTxData, onClose, decodedTxData: tx }: Props): ReactElement => { + let body + // If we are dealing with a multiSend + // decodedTxData is of type DataDecodedParameter + if (isDataDecodedParameterValue(tx)) { + const txValue = fromTokenUnit(tx.value, nativeCoin.decimals) + + body = ( + <> + + {tx.dataDecoded?.parameters.map((p, index) => getParameterElement(p, index))} + + ) + } else { + // If we are dealing with a single tx + // decodedTxData is of type DecodedData + body = <>{tx.parameters.map((p, index) => getParameterElement(p, index))} + } + + return ( + <> + + + + + {body} + + ) +} diff --git a/src/routes/safe/components/Apps/components/ConfirmTxModal/ReviewConfirm.tsx b/src/routes/safe/components/Apps/components/ConfirmTxModal/ReviewConfirm.tsx new file mode 100644 index 00000000..0a775471 --- /dev/null +++ b/src/routes/safe/components/Apps/components/ConfirmTxModal/ReviewConfirm.tsx @@ -0,0 +1,260 @@ +import React, { useEffect, useMemo, useState } from 'react' +import { ModalFooterConfirmation } from '@gnosis.pm/safe-react-components' +import styled from 'styled-components' +import { useDispatch } from 'react-redux' + +import DividerLine from 'src/components/DividerLine' +import TextBox from 'src/components/TextBox' +import ModalTitle from 'src/components/ModalTitle' +import Hairline from 'src/components/layout/Hairline' +import Heading from 'src/components/layout/Heading' +import { createTransaction } from 'src/logic/safe/store/actions/createTransaction' +import { MULTI_SEND_ADDRESS } from 'src/logic/contracts/safeContracts' +import { DELEGATE_CALL, TX_NOTIFICATION_TYPES, CALL } from 'src/logic/safe/transactions' +import { encodeMultiSendCall } from 'src/logic/safe/transactions/multisend' +import { getNetworkInfo } from 'src/config' +import { EstimationStatus, useEstimateTransactionGas } from 'src/logic/hooks/useEstimateTransactionGas' +import { TransactionFees } from 'src/components/TransactionsFees' +import { EditableTxParameters } from 'src/routes/safe/components/Transactions/helpers/EditableTxParameters' +import { TxParametersDetail } from 'src/routes/safe/components/Transactions/helpers/TxParametersDetail' +import { md, lg, sm } from 'src/theme/variables' +import { TxParameters } from 'src/routes/safe/container/hooks/useTransactionParameters' +import AddressInfo from 'src/components/AddressInfo' +import { DecodeTxs, BasicTxInfo } from 'src/components/DecodeTxs' +import { fetchTxDecoder } from 'src/utils/decodeTx' +import { DecodedData } from 'src/types/transactions/decode.d' +import { fromTokenUnit } from 'src/logic/tokens/utils/humanReadableValue' + +import GasEstimationInfo from '../GasEstimationInfo' +import { ConfirmTxModalProps, DecodedTxDetail } from '.' + +const { nativeCoin } = getNetworkInfo() + +const StyledTextBox = styled(TextBox)` + max-width: 444px; +` + +const Container = styled.div` + max-width: 480px; + padding: ${md} ${lg} 0; +` +const TransactionFeesWrapper = styled.div` + background-color: ${({ theme }) => theme.colors.background}; + padding: ${sm} ${lg}; + margin-bottom: 15px; +` + +const FooterWrapper = styled.div` + margin-bottom: 15px; +` + +const DecodeTxsWrapper = styled.div` + margin: 24px -24px; +` + +type Props = ConfirmTxModalProps & { + areTxsMalformed: boolean + showDecodedTxData: (decodedTxDetails: DecodedTxDetail) => void + hidden: boolean // used to prevent re-rendering the modal each time a tx is inspected +} + +export const ReviewConfirm = ({ + app, + txs, + safeAddress, + ethBalance, + safeName, + params, + hidden, + onUserConfirm, + onClose, + onTxReject, + areTxsMalformed, + showDecodedTxData, +}: Props): React.ReactElement => { + const [estimatedSafeTxGas, setEstimatedSafeTxGas] = useState(0) + const isMultiSend = txs.length > 1 + const [decodedData, setDecodedData] = useState(null) + const dispatch = useDispatch() + + const txRecipient: string | undefined = useMemo(() => (isMultiSend ? MULTI_SEND_ADDRESS : txs[0]?.to), [ + txs, + isMultiSend, + ]) + const txData: string | undefined = useMemo(() => (isMultiSend ? encodeMultiSendCall(txs) : txs[0]?.data), [ + txs, + isMultiSend, + ]) + const txValue: string | undefined = useMemo( + () => (isMultiSend ? '0' : txs[0]?.value && fromTokenUnit(txs[0]?.value, nativeCoin.decimals)), + [txs, isMultiSend], + ) + + const operation = useMemo(() => (isMultiSend ? DELEGATE_CALL : CALL), [isMultiSend]) + const [manualSafeTxGas, setManualSafeTxGas] = useState(0) + const [manualGasPrice, setManualGasPrice] = useState() + + const { + gasLimit, + gasPriceFormatted, + gasEstimation, + isOffChainSignature, + isCreation, + isExecution, + gasCostFormatted, + txEstimationExecutionStatus, + } = useEstimateTransactionGas({ + txData: txData || '', + txRecipient, + operation, + txAmount: txValue, + safeTxGas: manualSafeTxGas, + manualGasPrice, + }) + + useEffect(() => { + if (params?.safeTxGas) { + setEstimatedSafeTxGas(gasEstimation) + } + }, [params, gasEstimation]) + + // Decode tx data. + useEffect(() => { + const decodeTxData = async () => { + const res = await fetchTxDecoder(txData) + setDecodedData(res) + } + + decodeTxData() + }, [txData]) + + const handleTxRejection = () => { + onTxReject() + onClose() + } + + const handleUserConfirmation = (safeTxHash: string): void => { + onUserConfirm(safeTxHash) + onClose() + } + + const confirmTransactions = async (txParameters: TxParameters) => { + await dispatch( + createTransaction( + { + safeAddress, + to: txRecipient, + valueInWei: txValue, + txData, + operation, + origin: app.id, + navigateToTransactionsTab: false, + txNonce: txParameters.safeNonce, + safeTxGas: txParameters.safeTxGas + ? Number(txParameters.safeTxGas) + : Math.max(params?.safeTxGas || 0, estimatedSafeTxGas), + ethParameters: txParameters, + notifiedTransaction: TX_NOTIFICATION_TYPES.STANDARD_TX, + }, + handleUserConfirmation, + handleTxRejection, + ), + ) + } + + const closeEditModalCallback = (txParameters: TxParameters) => { + const oldGasPrice = Number(gasPriceFormatted) + const newGasPrice = Number(txParameters.ethGasPrice) + const oldSafeTxGas = Number(gasEstimation) + const newSafeTxGas = Number(txParameters.safeTxGas) + + if (newGasPrice && oldGasPrice !== newGasPrice) { + setManualGasPrice(txParameters.ethGasPrice) + } + + if (newSafeTxGas && oldSafeTxGas !== newSafeTxGas) { + setManualSafeTxGas(newSafeTxGas) + } + } + + return ( + + {(txParameters, toggleEditMode) => ( + + )} + + ) +} diff --git a/src/routes/safe/components/Apps/components/ConfirmTxModal/SafeAppLoadError.tsx b/src/routes/safe/components/Apps/components/ConfirmTxModal/SafeAppLoadError.tsx new file mode 100644 index 00000000..feddb412 --- /dev/null +++ b/src/routes/safe/components/Apps/components/ConfirmTxModal/SafeAppLoadError.tsx @@ -0,0 +1,47 @@ +import React, { ReactElement } from 'react' +import { Icon, Text, Title, ModalFooterConfirmation } from '@gnosis.pm/safe-react-components' +import styled from 'styled-components' +import { ConfirmTxModalProps } from '.' + +const IconText = styled.div` + display: flex; + align-items: center; + + span { + margin-right: 4px; + } +` + +const FooterWrapper = styled.div` + margin-top: 15px; +` + +export const SafeAppLoadError = ({ onTxReject, onClose }: ConfirmTxModalProps): ReactElement => { + const handleTxRejection = () => { + onTxReject() + onClose() + } + + return ( + <> + + + Transaction error + + + This Safe App initiated a transaction which cannot be processed. Please get in touch with the developer of this + Safe App for more information. + + + + handleTxRejection()} + handleOk={() => {}} + okDisabled={true} + okText="Submit" + /> + + + ) +} diff --git a/src/routes/safe/components/Apps/components/ConfirmTxModal/index.tsx b/src/routes/safe/components/Apps/components/ConfirmTxModal/index.tsx new file mode 100644 index 00000000..ebadeded --- /dev/null +++ b/src/routes/safe/components/Apps/components/ConfirmTxModal/index.tsx @@ -0,0 +1,72 @@ +import React, { ReactElement, useState } from 'react' +import { Transaction } from '@gnosis.pm/safe-apps-sdk-v1' + +import Modal from 'src/components/Modal' +import { SafeApp } from 'src/routes/safe/components/Apps/types.d' +import { TransactionParams } from 'src/routes/safe/components/Apps/components/AppFrame' +import { mustBeEthereumAddress } from 'src/components/forms/validator' +import { SafeAppLoadError } from './SafeAppLoadError' +import { ReviewConfirm } from './ReviewConfirm' +import { DecodedDataParameterValue, DecodedData } from 'src/types/transactions/decode' +import { DecodedTxDetail } from './DecodedTxDetail' + +export type ConfirmTxModalProps = { + isOpen: boolean + app: SafeApp + txs: Transaction[] + params?: TransactionParams + safeAddress: string + safeName: string + ethBalance: string + onUserConfirm: (safeTxHash: string) => void + onTxReject: () => void + onClose: () => void +} + +const isTxValid = (t: Transaction): boolean => { + if (!['string', 'number'].includes(typeof t.value)) { + return false + } + + if (typeof t.value === 'string' && !/^(0x)?[0-9a-f]+$/i.test(t.value)) { + return false + } + + const isAddressValid = mustBeEthereumAddress(t.to) === undefined + return isAddressValid && !!t.data && typeof t.data === 'string' +} + +export type DecodedTxDetail = DecodedDataParameterValue | DecodedData | undefined + +export const ConfirmTxModal = (props: ConfirmTxModalProps): ReactElement | null => { + const [decodedTxDetails, setDecodedTxDetails] = useState() + const areTxsMalformed = props.txs.some((t) => !isTxValid(t)) + + const showDecodedTxData = setDecodedTxDetails + const hideDecodedTxData = () => setDecodedTxDetails(undefined) + + const closeDecodedTxDetail = () => { + hideDecodedTxData() + props.onClose() + } + + return ( + + {areTxsMalformed && } + {decodedTxDetails && ( + + )} + + + ) +} diff --git a/src/types/transactions/decode.d.ts b/src/types/transactions/decode.d.ts new file mode 100644 index 00000000..8beb92e7 --- /dev/null +++ b/src/types/transactions/decode.d.ts @@ -0,0 +1,24 @@ +export type DecodedDataBasicParameter = { + name: string + type: string + value: string +} +export type DecodedDataParameterValue = { + operation: 0 | 1 + to: string + value: string + data: string + dataDecoded: { + method: string + parameters: DecodedDataBasicParameter[] + } | null +} + +export type DecodedDataParameter = { + valueDecoded?: DecodedDataParameterValue[] +} & DecodedDataBasicParameter + +export type DecodedData = { + method: string + parameters: DecodedDataParameter[] +} diff --git a/src/utils/decodeTx.ts b/src/utils/decodeTx.ts new file mode 100644 index 00000000..1ab6f3c0 --- /dev/null +++ b/src/utils/decodeTx.ts @@ -0,0 +1,18 @@ +import axios from 'axios' + +import { getTxServiceUrl } from 'src/config' +import { DecodedData } from 'src/types/transactions/decode.d' + +export const fetchTxDecoder = async (txData: string): Promise => { + if (!txData?.length || txData === '0x') { + return null + } + + const url = `${getTxServiceUrl()}/data-decoder/` + try { + const res = await axios.post(url, { data: txData }) + return res.data + } catch (error) { + return null + } +} diff --git a/yarn.lock b/yarn.lock index 71abef68..00a9ec29 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1596,9 +1596,9 @@ solc "0.5.14" truffle "^5.1.21" -"@gnosis.pm/safe-react-components@https://github.com/gnosis/safe-react-components.git#f610327": +"@gnosis.pm/safe-react-components@https://github.com/gnosis/safe-react-components.git#80f5db6": version "0.5.0" - resolved "https://github.com/gnosis/safe-react-components.git#f610327c109810547513079196514b05cda63844" + resolved "https://github.com/gnosis/safe-react-components.git#80f5db672d417ea410d58c8d713e46e16e3c7e7f" dependencies: classnames "^2.2.6" react-media "^1.10.0" From 1c3b1fb37b3cc1243b2251c2739309132455d3dc Mon Sep 17 00:00:00 2001 From: Mikhail Mikheev Date: Wed, 24 Mar 2021 14:01:37 +0400 Subject: [PATCH 12/15] Feature: Update 1inch app (#2076) * update 1inch hash --- src/routes/safe/components/Apps/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/safe/components/Apps/utils.ts b/src/routes/safe/components/Apps/utils.ts index 6d8a8c7d..88cb8184 100644 --- a/src/routes/safe/components/Apps/utils.ts +++ b/src/routes/safe/components/Apps/utils.ts @@ -26,7 +26,7 @@ export type StaticAppInfo = { export const staticAppsList: Array = [ // 1inch { - url: `${process.env.REACT_APP_IPFS_GATEWAY}/QmRWtuktjfU6WMAEJFgzBC4cUfqp3FF5uN9QoWb55SdGG5`, + url: `${process.env.REACT_APP_IPFS_GATEWAY}/QmUXF1yVGdqUfMbhNyfM3jpP6Bw66cYnKPoWq6iHkhd3Aw`, disabled: false, networks: [ETHEREUM_NETWORK.MAINNET], }, From 8bea5cfc8818c095d051efdd45c56db4c6204d73 Mon Sep 17 00:00:00 2001 From: lukasschor Date: Wed, 24 Mar 2021 11:12:34 +0100 Subject: [PATCH 13/15] (Fix) Update to new background color everywhere (#2068) * change to new background color everywhere --- src/routes/safe/components/AddressBook/style.ts | 2 +- src/routes/safe/components/Balances/Coins/styles.ts | 2 +- src/routes/safe/components/Settings/Advanced/style.ts | 2 +- .../Settings/ManageOwners/AddOwnerModal/screens/Review/style.ts | 2 +- .../ManageOwners/ReplaceOwnerModal/screens/Review/style.ts | 2 +- src/routes/safe/components/Settings/ManageOwners/style.ts | 2 +- src/routes/safe/components/Settings/SpendingLimit/style.ts | 2 +- src/theme/mui.ts | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/routes/safe/components/AddressBook/style.ts b/src/routes/safe/components/AddressBook/style.ts index f0e6c980..a8314a31 100644 --- a/src/routes/safe/components/AddressBook/style.ts +++ b/src/routes/safe/components/AddressBook/style.ts @@ -14,7 +14,7 @@ export const styles = createStyles({ }, hide: { '&:hover': { - backgroundColor: '#fff3e2', + backgroundColor: '#f7f5f5', }, '&:hover $actions': { visibility: 'initial', diff --git a/src/routes/safe/components/Balances/Coins/styles.ts b/src/routes/safe/components/Balances/Coins/styles.ts index 3c10059d..ae4ae6ac 100644 --- a/src/routes/safe/components/Balances/Coins/styles.ts +++ b/src/routes/safe/components/Balances/Coins/styles.ts @@ -12,7 +12,7 @@ export const styles = createStyles({ }, hide: { '&:hover': { - backgroundColor: '#fff3e2', + backgroundColor: '#f7f5f5', }, '&:hover $actions': { visibility: 'initial', diff --git a/src/routes/safe/components/Settings/Advanced/style.ts b/src/routes/safe/components/Settings/Advanced/style.ts index 272453bb..69925f4f 100644 --- a/src/routes/safe/components/Settings/Advanced/style.ts +++ b/src/routes/safe/components/Settings/Advanced/style.ts @@ -8,7 +8,7 @@ export const styles = createStyles({ }, hide: { '&:hover': { - backgroundColor: '#fff3e2', + backgroundColor: '#f7f5f5', }, '&:hover $actions': { visibility: 'initial', diff --git a/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/Review/style.ts b/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/Review/style.ts index 1a94ae9b..78644036 100644 --- a/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/Review/style.ts +++ b/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/Review/style.ts @@ -64,7 +64,7 @@ export const styles = createStyles({ selectedOwner: { padding: sm, alignItems: 'center', - backgroundColor: '#fff3e2', + backgroundColor: '#f7f5f5', }, user: { justifyContent: 'left', diff --git a/src/routes/safe/components/Settings/ManageOwners/ReplaceOwnerModal/screens/Review/style.ts b/src/routes/safe/components/Settings/ManageOwners/ReplaceOwnerModal/screens/Review/style.ts index 0cf8e781..ffa58763 100644 --- a/src/routes/safe/components/Settings/ManageOwners/ReplaceOwnerModal/screens/Review/style.ts +++ b/src/routes/safe/components/Settings/ManageOwners/ReplaceOwnerModal/screens/Review/style.ts @@ -69,7 +69,7 @@ export const styles = createStyles({ selectedOwnerAdded: { padding: sm, alignItems: 'center', - backgroundColor: '#fff3e2', + backgroundColor: '#f7f5f5', }, user: { justifyContent: 'left', diff --git a/src/routes/safe/components/Settings/ManageOwners/style.ts b/src/routes/safe/components/Settings/ManageOwners/style.ts index 957a20d0..0e9c4109 100644 --- a/src/routes/safe/components/Settings/ManageOwners/style.ts +++ b/src/routes/safe/components/Settings/ManageOwners/style.ts @@ -14,7 +14,7 @@ export const styles = createStyles({ }, hide: { '&:hover': { - backgroundColor: '#fff3e2', + backgroundColor: '#f7f5f5', }, '&:hover $actions': { visibility: 'initial', diff --git a/src/routes/safe/components/Settings/SpendingLimit/style.ts b/src/routes/safe/components/Settings/SpendingLimit/style.ts index 41a54264..0b8a9568 100644 --- a/src/routes/safe/components/Settings/SpendingLimit/style.ts +++ b/src/routes/safe/components/Settings/SpendingLimit/style.ts @@ -21,7 +21,7 @@ export const useStyles = makeStyles( }, hide: { '&:hover': { - backgroundColor: '#fff3e2', + backgroundColor: '#f7f5f5', }, '&:hover $actions': { visibility: 'initial', diff --git a/src/theme/mui.ts b/src/theme/mui.ts index 54562d69..4d793d54 100644 --- a/src/theme/mui.ts +++ b/src/theme/mui.ts @@ -455,7 +455,7 @@ export const DropdownListTheme = { }, button: { '&:hover': { - backgroundColor: '#fff3e2', + backgroundColor: '#f7f5f5', }, }, }, From 1b44f71485ddaba161e3cf6a77a64f4412333850 Mon Sep 17 00:00:00 2001 From: Daniel Sanchez Date: Wed, 24 Mar 2021 11:39:35 +0100 Subject: [PATCH 14/15] Update Compound safe app (#2078) --- src/routes/safe/components/Apps/utils.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/routes/safe/components/Apps/utils.ts b/src/routes/safe/components/Apps/utils.ts index a2e25269..5ff31606 100644 --- a/src/routes/safe/components/Apps/utils.ts +++ b/src/routes/safe/components/Apps/utils.ts @@ -3,7 +3,6 @@ import memoize from 'lodash.memoize' import { SafeApp, SAFE_APP_FETCH_STATUS } from './types.d' -import { getGnosisSafeAppsUrl } from 'src/config' import { getContentFromENS } from 'src/logic/wallets/getWeb3' import appsIconSvg from 'src/assets/icons/apps.svg' import { ETHEREUM_NETWORK } from 'src/config/networks/network.d' @@ -17,7 +16,6 @@ const removeLastTrailingSlash = (url) => { return url } -const gnosisAppsUrl = removeLastTrailingSlash(getGnosisSafeAppsUrl()) export type StaticAppInfo = { url: string disabled: boolean @@ -56,7 +54,11 @@ export const staticAppsList: Array = [ networks: [ETHEREUM_NETWORK.RINKEBY, ETHEREUM_NETWORK.XDAI], }, // Compound - { url: `${gnosisAppsUrl}/compound`, disabled: false, networks: [ETHEREUM_NETWORK.MAINNET, ETHEREUM_NETWORK.RINKEBY] }, + { + url: `${process.env.REACT_APP_IPFS_GATEWAY}/QmX31xCdhFDmJzoVG33Y6kJtJ5Ujw8r5EJJBrsp8Fbjm7k`, + disabled: false, + networks: [ETHEREUM_NETWORK.MAINNET, ETHEREUM_NETWORK.RINKEBY], + }, // dHedge { url: `${process.env.REACT_APP_IPFS_GATEWAY}/QmaiemnumMaaK9wE1pbMfm3YSBUpcFNgDh3Bf6VZCZq57Q`, From 8b35069e15e970dd8e27c9d44f527e3cd001c4a1 Mon Sep 17 00:00:00 2001 From: Mikhail Mikheev Date: Wed, 24 Mar 2021 14:50:24 +0400 Subject: [PATCH 15/15] Remove padding for iframe container (#1937) * remove padding for iframe container * update idle safe app url --- src/routes/safe/components/Apps/components/AppFrame.tsx | 1 + src/routes/safe/components/Apps/utils.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/routes/safe/components/Apps/components/AppFrame.tsx b/src/routes/safe/components/Apps/components/AppFrame.tsx index 62097c63..02d41f29 100644 --- a/src/routes/safe/components/Apps/components/AppFrame.tsx +++ b/src/routes/safe/components/Apps/components/AppFrame.tsx @@ -56,6 +56,7 @@ const AppWrapper = styled.div` const StyledCard = styled(Card)` flex-grow: 1; + padding: 0; ` const StyledIframe = styled.iframe` diff --git a/src/routes/safe/components/Apps/utils.ts b/src/routes/safe/components/Apps/utils.ts index 5ff31606..52ca818f 100644 --- a/src/routes/safe/components/Apps/utils.ts +++ b/src/routes/safe/components/Apps/utils.ts @@ -67,7 +67,7 @@ export const staticAppsList: Array = [ }, // Idle { - url: `${process.env.REACT_APP_IPFS_GATEWAY}/QmVkGHm6gfQumJhnRfFCh7m2oSYwLXb51EKHzChpcV9J3N`, + url: `${process.env.REACT_APP_IPFS_GATEWAY}/QmTvrLwJtyjG8QFHgvqdPhcV5DBMQ7oZceSU4uvPw9vQaj`, disabled: false, networks: [ETHEREUM_NETWORK.MAINNET, ETHEREUM_NETWORK.RINKEBY], },